简体   繁体   English

我如何专门化我的std :: string模板

[英]How do i specialize my template for std::string

I have the following templated function 我有以下模板化功能

template <typename As, typename std::enable_if<
std::is_arithmetic<As>::value, As>::type* = nullptr   > 
As getStringAs(const std::string& arg_name)
{
    std::istringstream istr(arg_name);
    As val;
    istr >> val;
    if (istr.fail())
        throw std::invalid_argument(arg_name);
    return val;
}

And i would like to use it like this: 我想这样使用它:

getStringAs<float>("2.f");

What would be a good way to specialize the function for std::string so that i can write 什么是专门针对std::string的功能的好方法,以便我可以编写

getStringAs<std::string>("2.f");

I have tried all my known ways but they all seem to fail due to the ambiguity generated by the default type of the std::enable_if . 我已经尝试了所有已知的方法,但是由于默认类型std::enable_if产生的歧义,它们似乎都失败了。 For example: if i write: 例如:如果我写:

template<>
std::string getStringAs<std::string>(const std::string& arg_name)
{    
}

This will not match any template overload. 这将不匹配任何模板重载。 If i add a second type, this will generate an ambiguity error. 如果我添加第二种类型,这将产生歧义错误。 I have tried google-in but the only thing i could find was about tag dispatch but that would make the call ugly on the user side. 我已经尝试了google-in,但是我唯一能找到的是关于标签分发的信息,但这会使用户端的调用变得难看。 I was thinking at the very ugly solution of using a macro definition for replacing getStringAs<std::string> with a dispatch tag. 我在考虑使用宏定义将getStringAs<std::string>替换为调度标记的非常丑陋的解决方案。

Thank you! 谢谢!

I usually use function overloading to resolve such problems. 我通常使用函数重载来解决此类问题。 It allows you to easily extend the functions for more types and you need to use SFINAE only where necessary (for example, for std::is_arithmetic ). 它使您可以轻松地将函数扩展为更多类型,并且仅在必要时才需要使用SFINAE(例如,对于std::is_arithmetic )。 Since you cannot overload by return type, this only works if you store the result in one of the arguments. 由于不能按返回类型重载,因此仅当将结果存储在参数之一中时,此方法才有效。

template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value>::type
getStringAsImpl(std::string const& in, T& out)
{
    std::istringstream sstr(in);
    sstr >> out;
    if (sstr.fail())
    {
        throw std::invalid_argument(in);
    }
}

void getStringAsImpl(std::string const& in, std::string& out)
{
    out = in;
}

template <typename T>
T getStringAs(std::string const& in)
{
    T out;
    getStringAsImpl(in, out);
    return out;
}

One way is to move the SFINAE to the return type: 一种方法是将SFINAE移至返回类型:

template <typename As>
auto getStringAs(const std::string& arg_name)
    -> typename std::enable_if<std::is_arithmetic<As>::value, As>::type;

template <typename As>
auto getStringAs(const std::string& arg_name)
    -> typename std::enable_if<std::is_same<As, std::string>::value, As>::type;

but they all seem to fail due to the ambiguity generated by the default type of the enable_if 但由于enable_if的默认类型产生的歧义,它们似乎都失败了

The problem is that if you write 问题是如果你写

template <> 
std::string getStringAs<std::string> (const std::string& arg_name)
 { return arg_name; }

the specialization doesn't match the main template because std::is_arithmetic<std::string>::value is false so the second template parameter isn't enabled. 该专业化与主模板不匹配,因为std::is_arithmetic<std::string>::value为false,因此第二个模板参数未启用。

A possible solution (I prefer the solution suggested by bolov, but just to explore other ways and better understand the problem) is to enable the second template parameter with std::string as follows 可能的解决方案(我更喜欢bolov建议的解决方案,但只是为了探索其他方式并更好地理解问题)是使用std::string启用第二个模板参数,如下所示

template <typename As, typename std::enable_if<
      std::is_arithmetic<As>::value 
   || std::is_same<As, std::string>::value, bool>::type = true> 
As getStringAs(const std::string& arg_name)
{
    std::istringstream istr(arg_name);
    As val;
    istr >> val;
    if (istr.fail())
        throw std::invalid_argument(arg_name);

    return val;
}

now you can full specialize as usual 现在您可以像往常一样全神贯注

template <> 
std::string getStringAs<std::string> (const std::string& arg_name)
 { return arg_name; }

Observe that std::string now matches both getStringAs() versions but the compiler choose the second because is more specialized. 观察到std::string现在可以同时匹配两个getStringAs()版本,但是编译器选择第二个版本是因为它更加专业。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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