Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 可变模板无法匹配常量和非常量std::string_C++_C++11_Variadic Templates - Fatal编程技术网

C++ 可变模板无法匹配常量和非常量std::string

C++ 可变模板无法匹配常量和非常量std::string,c++,c++11,variadic-templates,C++,C++11,Variadic Templates,我在构建变量模板时遇到了问题,在该模板中,扩展函数正确地匹配非常量和常量std::string。我有一个通用的匹配函数,它在某些情况下被调用 我已将代码简化为以下示例。不是字符串的东西应该在泛型函数中结束。作为字符串的东西应该在第二个函数结束,该函数额外输出“string” #包括 #包括 模板 无效扩展\u异常(X&ex、T&value) { 这是一个相当棘手的问题,T&&是一个所谓的通用参考,但std::string&&不是(不涉及类型推断)。请参阅以获得良好的解释。这里有一个修复方法: t

我在构建变量模板时遇到了问题,在该模板中,扩展函数正确地匹配非常量和常量
std::string
。我有一个通用的匹配函数,它在某些情况下被调用

我已将代码简化为以下示例。不是字符串的东西应该在泛型函数中结束。作为字符串的东西应该在第二个函数结束,该函数额外输出“string”

#包括
#包括
模板
无效扩展\u异常(X&ex、T&value)
{

这是一个相当棘手的问题,
T&&
是一个所谓的通用参考,但
std::string&&
不是(不涉及类型推断)。请参阅以获得良好的解释。这里有一个修复方法:

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" ) );
}
模板
无效扩展\异常\异常(X&ex,T&value,…)
{

这是一个相当棘手的问题,
T&&
是一个所谓的通用参考,但
std::string&&
不是(不涉及类型推断)。请参阅以获得良好的解释。这里有一个修复方法:

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" ) );
}
模板
无效扩展\异常\异常(X&ex,T&value,…)
{

ex您不能将非右值绑定到右值引用,因此
string&
不起作用,但是
const std::string&
适用于
var
。但是,
var
不是常量,因此到达有效重载的最短路径是将
t&&
折叠到
std::string&
,然后取第一条路径


您需要找出互斥的类型,或者使用SFINAE编写两个在正确类型的参数上相互排斥的类型。

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


您需要找出互斥的类型,或者使用SFINAE在正确类型的参数上编写两个相互排斥的类型。

这是因为您的字符串版本只捕获作为右值传递的字符串。左值将传递给泛型函数。T&&和string&&&,或者更一般的T之间存在巨大差异&&和U&,如果T是一个模板参数,而U不是(意思是,U是某个指定的类型)

要使函数按您所希望的方式工作,您需要做的是添加另一个重载:

template<typename X>
void extend_exception( X & ex, std::string const& value )
{
  ex << "STRING: " << value << std::endl;
}
模板
无效扩展_异常(X&ex,标准::字符串常量和值)
{

这是因为您的字符串版本只捕获作为右值传递的字符串。左值将传递给泛型函数。如果T是模板参数而U不是(意味着,U是某个指定类型),则T&&和string&&,或者更一般的T&&和U&&&之间存在巨大差异。请参阅Scott Meyers关于

要使函数按您所希望的方式工作,您需要做的是添加另一个重载:

template<typename X>
void extend_exception( X & ex, std::string const& value )
{
  ex << "STRING: " << value << std::endl;
}
模板
无效扩展_异常(X&ex,标准::字符串常量和值)
{

ex我重新审视了这个问题,并提出了一个涉及使用类标记的解决方案。我曾与写过一篇文章。

我重新审视了这个问题,并提出了一个涉及使用类标记的解决方案。我曾与写过一篇文章。

仅通过值传递似乎有效,尽管我怀疑它是否“正确”@Griwes,是的,按值计算是有效的,但我不想不必要地复制东西。只是按值计算似乎有效,尽管我怀疑它是否“正确”@Griwes,是的,按值工作,但我不想不必要地复制东西。在它的用法上面定义了5行:
identity
是标识;)你可能想使用
std::decation
而不是
std::remove\u reference
,否则
对于
const std::string
测试失败。a本机使用
std::remove_cv
std::remove_reference
,但在这种情况下,
std::decay
的类型较少,并且是等效的。我无法测试这一点,因为在GCC 4.7(您的身份声明)之前不支持模板别名。您能验证我在示例中添加的参数(最后一次使用常量转换扩展_异常的调用)还可以使用此代码吗?是的,要在没有SFINAE的情况下正确使用它,需要为每个专用类型使用三个函数(这里是std::string)。在其用法上方定义了5行:
identity
是标识;)您可能希望使用
std::decay
而不是
std::remove_reference
,否则
是相同的
测试因
const std::string
而失败。a本机使用
std::remove_cv
std::remove_reference
,但
std::decay
在本例中的类型较少且等效。我无法测试这一点,因为直到GCC 4.7(您的标识声明)才支持模板别名。您能否验证我在示例中添加的参数(最后一次使用const_cast调用extend_exception)仍然可以使用此代码?是的,要在没有SFINAE的情况下正确使用它,每个专用类型(这里是std::string)需要三个函数。
&
也不能捕获可变引用。您需要添加两个其他重载。
&
也不能捕获可变引用。您需要添加两个其他重载。