C++ - 遍历元组和类型与常量参数的解析

13

我目前正在为元组编写算术运算符重载。该运算符迭代元组以对其每个单独元素执行操作。以下是 += 运算符的定义:

template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    return lhs;
}

template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    std::get< I >(lhs) += std::get< I >(rhs);
    return operator +=< Ts..., I + 1 >(lhs, rhs);
}

很不幸,当我试图调用运算符时,GCC 4.6无法决定应该使用哪个重载。例如:

std::tuple< int, int, int, int > a = std::make_tuple(1, 2, 3, 4), b = std::make_tuple(5, 6, 7, 8);
a += b;

会产生以下错误:

:/Workspace/raster/main.cpp:833:7:   instantiated from here
C:/Workspace/raster/main.cpp:809:45: error: no matching function for call to 'operator+=(std::tuple<int, int, int, int>&, const std::tuple<int, int, int, int>&)'
C:/Workspace/raster/main.cpp:809:45: note: candidates are:
C:/Workspace/raster/main.cpp:800:151: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I == sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
C:/Workspace/raster/main.cpp:806:83: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I != sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)

这很奇怪,因为std::enable_if的条件应该拒绝不适当的调用。目前,我有以下解决方法,实际上这是我的先前实现。上述版本实际上是一种简化尝试。

template< std::size_t I, typename... Ts >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    return lhs;
}

template< std::size_t I, typename... Ts >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    std::get< I >(lhs) += std::get< I >(rhs);
    return assignadd_impl< I + 1, Ts... >(lhs, rhs);
}

template< typename... Ts >
inline std::tuple< Ts... >& operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
    return assignadd_impl< 0, Ts... >(lhs, rhs);
}

这段代码编译并按预期工作。为什么简化版本会拒绝编译?谢谢。


如果您将第一个代码示例中的I模板参数移动到前面,就像第二个有效的示例中那样,会发生什么?这会改变什么吗? - Jeremiah Willcock
@Jeremiah Willcock - 很遗憾,不行。我尝试了许多变化,包括交换模板参数的顺序,但它们都产生相同的错误。 - pmjobin
1个回答

6
在函数或类模板中使用显式指定的模板参数需要将任何模板参数包出现在整个模板参数列表的末尾。将"Ts..."移动到模板参数列表的末尾,并相应地更改调用,使代码能够正常工作。根据当前C++0x草案的第14.8.2.1节,不在模板参数列表末尾的参数包无法从函数调用中推导出(这会导致您的原始代码失败),但在所有情况下显式指定operator+=的所有模板参数仍会导致SFINAE错误。以前的一个问题有一个链接,链接到了禁止此操作的准确文本;IBM的文档也表示这是一个错误。

确实它有效。我不知道在我的原始测试期间出了什么问题,因为有一次我反转了模板参数。但无论如何还是谢谢你。 :) - pmjobin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接