变量模板故障匹配const和非const std :: string

时间:2013-01-09 16:14:03

标签: c++ c++11 variadic-templates

我在构造可变参数模板时遇到问题,其中扩展函数正确匹配非const和const std::string。我有一个通用匹配函数,在某些情况下会被调用。

我已将代码缩减为以下示例。不是字符串的东西最终应该归结为泛型函数。作为字符串的东西应该在第二个函数处结束,该函数另外输出“STRING”。

#include <iostream>
#include <string>

template<typename X, typename T>
void extend_exception( X & ex, T&& value )
{
    ex << value << std::endl;
}

template<typename X>
void extend_exception( X & ex, std::string && value )
{
    ex << "STRING: " << value << std::endl;
}

template<typename X, typename TF, typename ... TR>
void extend_exception( X & ex, TF&& f, TR&& ... rest )
{
    extend_exception( ex, std::forward<TF>(f) );
    extend_exception( ex, std::forward<TR>(rest)... );
}

int main()
{
    extend_exception( std::cout, std::string( "Happy" ) );
    std::string var( "var" );
    extend_exception( std::cout, var );
    extend_exception( std::cout, var, std::string( "Combo" ),  const_cast<std::string const&>(var));
    return 0;
}

在上面的版本中,两个var使用不会传递给字符串函数。我已经尝试了各种其他方法来指定参数,但似乎没有办法解决这个问题:std::string && valuestd::string const & valuestd::string const && value。我也尝试了std::string & value,然后非const字符串匹配,但不是常量字符串匹配。这至少为我提供了两种不同的功能,但我怀疑我不应该这样做。

如何在这里编写一个函数来调用const,非const和临时字符串对象?

我正在使用g ++ 4.6.3

4 个答案:

答案 0 :(得分:4)

这非常棘手,T&&是所谓的通用引用,但std::string&&不是(不涉及类型推导)。有关详细说明,请参阅here。这是一个修复:

template<typename X, typename T>
void extend_exception_( X & ex, T&& value, ... )
{
  ex << value << std::endl;
}

template<typename X, typename T,
         typename = typename std::enable_if<
           std::is_same<std::string, typename std::decay<T>::type>::value>::type>
void extend_exception_( X & ex, T && value, int )
{
  ex << "STRING: " << value << std::endl;
}

template <typename T> using identity = T;

template<typename X, typename ... R>
void extend_exception( X & ex, R&& ... rest )
{
  identity<bool[]>{false,(extend_exception_(ex, std::forward<R>(rest), 0), false)...};
}

int main()
{
  extend_exception( std::cout, std::string( "Happy" ) );
  std::string var( "var" );
  extend_exception( std::cout, var );
  extend_exception( std::cout, var, std::string( "Combo" ) );
}

答案 1 :(得分:2)

您无法将非右值绑定到右值引用,因此string&&不起作用,但const std::string&适用于var。但是,var不是常量,因此有效的重载的最短路径是将T&&折叠到std::string&并获取第一个。

你需要弄清楚相互排斥的类型,或者使用SFINAE来编写两个在正确类型的参数上相互排斥的类型。

答案 2 :(得分:2)

这是因为你的字符串版本只捕获作为rvalues传递的字符串。左值将传递给泛型函数。 T&amp;&amp; amp;和T&amp;和字符串&amp;&amp;和更普遍的T&amp;&amp;和U&amp;&amp;,如果T是模板参数而U不是(意思是,U是某些指定的类型)。请参阅Scott Meyers关于universal references

的说明

为了使函数正常工作,您需要做的是添加另一个重载:

template<typename X>
void extend_exception( X & ex, std::string const& value )
{
  ex << "STRING: " << value << std::endl;
}

答案 3 :(得分:0)

我重新审视了这个问题并提出了一个涉及使用类标记的解决方案。我写了一篇文章full solution/discussion