Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if type can be an argument to boost::lexical_cast<string>

I have the following traits class(IsLexCastable) to check if a type can be converted to a string by calling boost::lexical_cast<string>. It erroneously returns true for vector<int>.

#include <iostream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

#include <boost/lexical_cast.hpp>

using namespace std;
using namespace boost;

namespace std
{
/// Adding to std since these are going to be part of it in C++14.
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
}

template <typename T, typename = void>
struct IsLexCastable : std::false_type
{
};

template <typename T>
struct IsLexCastable<T, std::enable_if_t<std::is_same<std::string, decltype(boost::lexical_cast<std::string>(std::declval<T>()))>::value> > : std::true_type
{
};

int main()
{
  vector<int> a = {1, 2, 3};
  //  cout << lexical_cast<string>(a) << endl;
  cout << IsLexCastable<decltype(a)>::value << endl;
  return 0;
}

This program prints 1, but lexical_cast<string>(a) results in a compile error. What is the right way to implement IsLexCastable?

(This was compiled with g++48 -std=c++11, and boost 1.55.0.)

like image 331
Pradhan Avatar asked Dec 30 '14 17:12

Pradhan


1 Answers

Your expression is not sufficient, as the lexical_cast function template takes everything and only reports errors via an internal static_assert. Instead test whether inserting the object into an std::ostream is valid:

template <typename T, typename=void>
struct IsLexCastable : std::false_type {};

// Can be extended to consider std::wostream as well for completeness
template <typename T>
struct IsLexCastable<T,
            decltype(void(std::declval<std::ostream&>() << std::declval<T>()))>
  : std::true_type {};

Demo.
That requirement is called OutputStreamable by the documentation, and the direct one imposed onto the source type.


Why did your implementation not work?

decltype only causes the instantiation of the declaration of a function template. The internal static assertion is triggered inside the definition of lexical_cast though, hence it cannot be used in SFINAE.

[temp.inst]/10:

If a function template or a member function template specialization is used in a way that involves overload resolution, a declaration of the specialization is implicitly instantiated (14.8.3).

like image 169
Columbo Avatar answered Sep 30 '22 06:09

Columbo