Pradhan Pradhan - 2 months ago 11
C++ Question

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
.)

Answer

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).

Comments