【问题标题】:Check if type can be an argument to boost::lexical_cast<string>检查 type 是否可以作为 boost::lexical_cast<string> 的参数
【发布时间】:2014-12-30 17:00:36
【问题描述】:

我有以下特征类(IsLexCastable) 来检查是否可以通过调用boost::lexical_cast&lt;string&gt; 将类型转换为字符串。它错误地为vector&lt;int&gt; 返回true

#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;
}

此程序打印1,但lexical_cast&lt;string&gt;(a) 导致编译错误。实现IsLexCastable的正确方法是什么?

(这是用g++48 -std=c++11boost 1.55.0编译的。)

【问题讨论】:

    标签: c++ templates c++11 boost template-meta-programming


    【解决方案1】:

    您的表达不够充分,因为lexical_cast 函数模板接受了所有内容,并且仅通过内部static_assert 报告错误。而是测试将对象插入std::ostream 是否有效:

    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.
    该要求被the documentation 称为OutputStreamable,是对源类型施加的直接要求。


    为什么你的实现不起作用?

    decltype 只会导致函数模板的声明实例化。内部静态断言是在lexical_cast 的定义内触发的,因此不能在SFINAE 中使用。

    [temp.inst]/10:

    如果函数模板或成员函数模板特化 以涉及重载决议的方式使用,特化的声明被隐式实例化(14.8.3)。

    【讨论】:

    • 此代码可能有效,但实际上它的设计比 OP 的代码更糟糕,因为您使用的是 boost::lexical_cast 的实现细节。如果你想走这条路,当你在不合适的类型上使用它时,你也可以复制并粘贴在 boost::lexical_cast 中失败的静态断言。这个想法是让代码告诉 boost::lexical_cast 是否可以工作,而不管它是如何实现的。
    • @NirFriedman 这不是一些实现细节,而是库的实际要求。
    • 谢谢。会试试这个。你能解释一下为什么现有的代码会失败吗?它具有您的专业化的调用,但包含在对 is_same 的元调用中。
    • @Pradhan SFINAE 仅在直接上下文中起作用。调用boost::lexical_cast&lt;std::string&gt;(std::declval&lt;T&gt;()) 在直接上下文中的格式非常好,因为有这样一个函数模板。该函数模板在实例化时是否真正编译并不重要。
    • @T.C.我认为这种解释令人恼火。直接上下文更多地是关于函数声明。在这里,定义没有被实例化的事实很重要。
    【解决方案2】:

    Columbo 的回答回答了这个问题,但我在适应输入流时遇到了问题。我的用例是我想调用 lexical_cast 将字符串转换为 T。Boost 提供了 has_right_shift 和 has_left_shift,它们很有效,并且应该为类似的构造提供更大的灵活性。

    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 {};
    

    【讨论】:

    • 这里缺少一些细节,例如 has_left_shift 或 has_right_shift 有更多的参数,如果你仔细看,你会发现除非你指定 LHS 是 ostream 或 istream,否则你'正在询问是否有移位运算符,例如 boost.org/doc/libs/1_69_0/libs/type_traits/doc/html/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-25
    • 2012-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多