简体   繁体   中英

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

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

The answer by Columbo answers the question, but I had problems adapting to to an input stream. My use case was that I wanted to call lexical_cast to convert from string to T. Boost offers has_right_shift and has_left_shift, which worked and should allow more flexibility for similar constructs.

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

template <typename T>
struct IsLexCastable<T,
        typename std::enable_if<boost::has_right_shift<T>::value>::type>
  : std::true_type {};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM