带前向引用和运算符的变量模板+ =

时间:2017-07-11 17:56:20

标签: c++ c++14 variadic-templates sfinae forward-reference

我有一个应该采用多个参数的函数,在将所有参数添加到*this之后,operator+=被重载并且为一个参数工作。功能看起来像

template <typename T, typename U>
struct are_equal :
    std::is_same<typename std::decay<T>::type, U>::type
{};

template<typename T>
template<typename... U>
std::enable_if_t<are_equal<U ..., Object<T>>::value>
Object<T>::addd(U &&... u)
{
//  *this += std::forward<U>(u)...;
}

可能我有两个问题。 1.我认为我应该用type_traits更改部分代码,但我的实验没有给出正确的结果。 注释行出错(其中operator +=

  

C2893无法专门化功能模板'enable_if&lt; _Test,_Ty&gt; :: type Object :: addd(U&amp;&amp; ...)'   C2672'Object :: addd':找不到匹配的重载函数

  1. 评论专栏中的字典(?)问题:

    *this += std::forward<U>(u)...;
    
  2. 错误:

      

    C2143语法错误:缺少';'在'...'之前

         

    C2059语法错误:'...'

         

    C3520'u':必须在此上下文中扩展参数包

    Operator+=适用于一个元素(我敢肯定)。

2 个答案:

答案 0 :(得分:4)

我认为你希望这个包扩展产生这样的东西:

*this += std::forward<U>(u_1),
*this += std::forward<U>(u_2),
// ...
*this += std::forward<U>(u_n);

*this += std::forward<U>(u)...;不起作用的原因是,粗略地说,由包扩展(但不是通过折叠表达式,见下文)生成的逗号不能使用作为运营商

经典的C ++之前的17种解决方法是使用虚拟数组:

using dummy_array = int[];
dummy_array{(*this += std::forward<U>(u), 0)..., 0};

请注意,此扩展产生的逗号不会用作运算符(而是用作元素初始值设定项的分隔符),因此不会应用上述限制。

上述代码段中的第一个, 0让我们忽略*this += blah的返回类型。
第二个, 0用于支持空参数包(否则将尝试创建一个空数组,这是不允许的。)

类型别名是必要的,因为编译器不允许您直接使用int[]{blah, blah}

作为using的替代方案,您可以使用类似

的内容
std::enable_if_t<1, int[]>{(std::cout << p, 0)..., 0};

另一个选择是创建一个实际数组而不是临时数组:

int dummy_array[]{(std::cout << p, 0)..., 0};
(void)dummy_array;

但我不太喜欢这个。

如果你有C ++ 17,你应该使用fold expressions代替:

((*this += std::forward<U>(u)), ...);

答案 1 :(得分:2)

我想你想要以下内容:

template <bool ... Bs> struct bools {};

template <bool ... Bs>
using all_of = std::is_same<bools<true, Bs...>, bools<Bs..., true>>;

template <typename T, typename ... Ts>
using are_equal = all_of<std::is_same<T, Ts>::value...>;

template<typename T>
template<typename... Us>
std::enable_if_t<are_equal<T, std::decay_t<Us>...>::value>
Object<T>::add(Us&&... u)
{
    const int dummy[] = {0, ((*this += std::forward<Us>(u)), 0)...};
    static_cast<void>(dummy);
}