Clang在折叠表达式中找不到模板二元运算符

时间:2017-08-08 13:28:10

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

这是我连接元组的二元运算符:

template <class... Args1, class... Args2>
constexpr decltype(auto) operator+(const std::tuple<Args1...> &tup1,
                                   const std::tuple<Args2...> &tup2) {
   return std::tuple_cat(tup1, tup2);
}

它在两个元组的编译器(gcc,clang)上都能很好地工作:

template <class Arg1, class Arg2>
constexpr decltype(auto) concat_test(Arg1 &&arg1, Arg2 &&arg2) {
   return arg1 + arg2;
}

但是当我尝试在折叠表达式中使用它时,如下所示:

template <class... Args>
constexpr decltype(auto) multiple_concat(Args &&... args) {
   return (args + ...);
}

gcc 7.1.1编译它没有任何错误,这与产生错误输出的clang 5.0不同:

  

错误:致电功能&#39;运营商+&#39;这在模板定义中既不可见,也不能由参数依赖查找找到

     

return(args + ... );

     

注意:在实例化函数模板特化&#39; multiple_concat&lt; std :: __ 1 :: tuple&amp;,std :: __ 1 :: tuple&amp;&gt;&#39;请求

     

multiple_concat (tup1,tup2);

     

注意:&#39;运营商+&#39;应在呼叫站点之前声明

     

constexpr decltype(auto)运算符 +(const std :: tuple&amp; tup1,const std :: tuple&amp; tup2)

这段代码是否格式错误,究竟是什么铿锵谈论?

3 个答案:

答案 0 :(得分:1)

由于其他答案没有出来并这样说:代码很好。这是历史悠久的Clang bug,会影响版本11。

答案 1 :(得分:0)

2018年8月:Xcode 9.0(大致等效于开源clang 4.0)仍无法编译此代码,而g ++可以正确完成此工作。

我知道无法使用闪亮的新模板折叠语法很痛苦,但是这是基于if constexpr(我们可以使用的下一个最佳方法)的解决方法。

template <typename T, typename... Ts>
constexpr decltype(auto) multiple_concat(T&& arg, Ts&&... rest) {
    if constexpr (sizeof ...(rest) == 0) {
        return arg;
    }
    else {  // recursively concatenate the tuple
        return arg + multiple_concat(std::forward<Ts>(rest) ...);
    }
}

Clang高兴地编译了这段代码。

答案 2 :(得分:0)

显然,不合格的查找失败。这使它可以使用Clang 6进行编译:

namespace std {
    template <class... Args1, class... Args2>
    constexpr decltype(auto) operator+(const ::std::tuple<Args1...> &tup1,
                                       const ::std::tuple<Args2...> &tup2) {
      return ::std::tuple_cat(tup1, tup2);
    }

    template <class... Args1, class... Args2>
    constexpr decltype(auto) operator+(::std::tuple<Args1...> &&tup1,
                                       ::std::tuple<Args2...> &&tup2) {
      return ::std::tuple_cat(tup1, tup2);
    }
}