可变模板的声明点 [英] Point of declaration for variadic template

查看:103
本文介绍了可变模板的声明点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么时候被认为是宣称的可变参数模板?这在clang ++ 3.4下编译,但不在g ++ 4.8.2下编译。

  template< typename T& 
const T& sum(const T& v){return v; }

template< typename T,typename ... Ts>
auto sum(const T& v,const Ts& ... params) - > decltype(v + sum(params ...));

template< typename T,typename ... Ts>
auto sum(const T& v,const Ts& ... params) - > decltype(v + sum(params ...)){
return v + sum(params ...);
}

int main(){
sum(1,2,3);
}

很明显,g ++不会匹配尾部返回类型中的函数本身。 g ++ 4.8.2的错误是:

  sum.cpp:在函数'int main()':
sum.cpp:13:16:error:没有匹配的函数调用'sum(int,int,int)'
sum(1,2,3);
^
sum.cpp:13:16:note:candidate are:
sum.cpp:2:10:note:template< class T& const T& sum(const T& v)
const T& sum(const T& v){return v; }
^
sum.cpp:2:10:note注意:模板参数扣除/替换失败:
sum.cpp:13:16:note:candidate expects 1 argument,3提供
sum(1,2,3);
^
sum.cpp:8:6:note:template< class T,class ... Ts> decltype((v + sum(sum :: params ...)))sum(const T& const Ts& ...)
auto sum(const T& v,const Ts& params) - > decltype(v + sum(params ...)){
^
sum.cpp:8:6:note:模板参数扣除/替换失败:
sum.cpp: 'template< class T,class ... Ts> decltype((v + sum(sum :: params ...)))sum(const T& const Ts& ...)[with T = int; Ts = {int,int}]':
sum.cpp:13:16:从这里需要
sum.cpp:5:74:错误:没有匹配的函数调用'sum ; const int&)'
auto sum(const T& v,const Ts& ... params) - > decltype(v + sum(params ...));
^
sum.cpp:5:74:note:candidate is:
sum.cpp:2:10:note:template< class T& const T& sum(const T& v)
const T& sum(const T& v){return v; }
^
sum.cpp:2:10:note注意:模板参数扣除/替换失败:
sum.cpp:5:74:note:candidate expects 1 argument,2提供
auto sum(const T& v,const Ts& ... params) - > decltype(v + sum(params ...));
^

补充:如果我删除可变参数模板的声明,clang ++和g ++给出错误。



Addum 2:我看到一个类似的问题以前被问过。我猜这里真正的问题是为什么它工作与一个编译器,而不是其他。另外,我可以使用g ++通过使用非原始参数sum()来在POI上强制ADL。



附录3:在clang ++和g ++:

  class A {
};
A运算符+(const A& const A&){
return A();
}

template< typename T>
const T& sum(const T& v){return v; }

/ *
template< typename T,typename ... Ts>
auto sum(const T& v,const Ts& ... params) - > decltype(v + sum(params ...));
* /

template< typename T,typename ... Ts>
auto sum(const T& v,const Ts& ... params) - > decltype(v + sum(params ...)){
return v + sum(params ...);
}

int main(){
// sum(1,2,3);
sum(A(),A(),A());
}


解决方案

http://stackoverflow.com/questions/3744400/trailing-return-type-using-decltype-with-a-variadic-template-function>这个问题的答案(Praetorian提供)表示,声明是只有在返回类型后才完成,并且GCC是正确的。我相信ang的行为也是允许的,但它不可移植。链接中的答案提供了一个使用traits类的解决方法,并且通常会执行这个工作,但是它有点尴尬,并且容易出错(因为您必须在单独的表达式中构造返回类型,该表达式可能与函数表达)。另一种可能的解决方法是使您的函数成为类模板的静态成员(然后添加一个自由函数转发给静态模板成员)。



还有一种解决方法你可以考虑,这是暗示在你的第二个例子,两个编译器都有效。当您在 A 上调用 sum()时,您将应用用户定义的类型作为参数。这包括参数依赖查找,这使得模板生成在 A 的命名空间中第二次查看 sum() code>(这恰恰是全局命名空间,与 sum()相同),这允许它在实例化期间找到可变函数模板。 p>

因此,如果您可以安排一个参数始终是需要ADL的用户定义类型,那么您可以依赖于第二阶段的重载分辨率来找到可变参数模板完全声明之后。所以,也许这样的东西可能满足你的需要:

 命名空间sum_impl {
struct Dummy {};

template< typename T>
T const& sum_helper(Dummy,T const& v){return v; }

template< typename T,typename ... Ts>
auto sum_helper(Dummy d,T const& v,Ts const& ... params)
- > decltype(v + sum_helper(d,params ...)){
return v + sum_helper(d,params ...);
}

template< typename ... P>
auto sum(P const& ... p)
- > decltype(sum_helper(Dummy {},p ...){
return sum_helper(Dummy {},p ...);
}
}
使用sum_impl :: sum ;


At what point is a variadic template considered "declared"? This compiles under clang++ 3.4, but not under g++ 4.8.2.

template <typename T>
const T &sum(const T &v) { return v; }

template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));

template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
    return v + sum(params...);
}

int main() {
    sum(1, 2, 3);
}

Apparently g++ won't match the function itself in the trailing return type. The error from g++ 4.8.2 is:

sum.cpp: In function 'int main()':
sum.cpp:13:16: error: no matching function for call to 'sum(int, int, int)'
     sum(1, 2, 3);
                ^
sum.cpp:13:16: note: candidates are:
sum.cpp:2:10: note: template<class T> const T& sum(const T&)
 const T &sum(const T &v) { return v; }
          ^
sum.cpp:2:10: note:   template argument deduction/substitution failed:
sum.cpp:13:16: note:   candidate expects 1 argument, 3 provided
     sum(1, 2, 3);
                ^
sum.cpp:8:6: note: template<class T, class ... Ts> decltype ((v + sum(sum::params ...))) sum(const T&, const Ts& ...)
 auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
      ^
sum.cpp:8:6: note:   template argument deduction/substitution failed:
sum.cpp: In substitution of 'template<class T, class ... Ts> decltype ((v + sum(sum::params ...))) sum(const T&, const Ts& ...) [with T = int; Ts = {int, int}]':
sum.cpp:13:16:   required from here
sum.cpp:5:74: error: no matching function for call to 'sum(const int&, const int&)'
 auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
                                                                          ^
sum.cpp:5:74: note: candidate is:
sum.cpp:2:10: note: template<class T> const T& sum(const T&)
 const T &sum(const T &v) { return v; }
          ^
sum.cpp:2:10: note:   template argument deduction/substitution failed:
sum.cpp:5:74: note:   candidate expects 1 argument, 2 provided
 auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
                                                                      ^

Addendum: If I delete the declaration of the variadic template, both clang++ and g++ give errors.

Addedum 2: I see that a similar question has been asked before. I guess the real question here is why it works with one compiler and not the other. Also, I can make it work with g++ by forcing ADL at the POI by using non-primitive arguments to sum().

Addendum 3: This works under both clang++ and g++:

class A {
};
A operator+(const A &, const A &) {
    return A();
}

template <typename T>
const T &sum(const T &v) { return v; }

/*
template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
*/

template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
    return v + sum(params...);
}

int main() {
    //sum(1, 2, 3);
    sum(A(), A(), A());
}

解决方案

As this question's answer (provided by Praetorian) indicates, the declaration is only complete after the return type, and GCC is correct. I believe clang's behavior is also allowable, but it's not portable. The answer in the link gives a workaround using a traits class, and that will usually do the job, but it's somewhat awkward and can be error prone (since you have to construct the return type in a separate expression which may differ subtlely from the function expression). Another possible workaround involves making your function a static member of a class template (and then adding a free function that forwards to the static template member).

There is another workaround that you can consider, which is hinted at in your second example which works on both compilers. When you call sum() on A, you are applying a user-defined type as a parameter. This involves argument-dependent-lookup, which causes the template generation to look a second time for overloads of sum() in the namespace of A (which happens to be the global namespace, the same as sum()), and this allows it to find the variadic function template during instantiation.

Thus, if you can arrange for one of your arguments to always be a user-defined type requiring ADL, you can then rely on the second phase of overload resolution to find the variadic template after it's fully declared. So, perhaps something like this might meet your need:

namespace sum_impl {
    struct Dummy { };

    template <typename T>
    T const &sum_helper(Dummy, T const &v) { return v; }

    template <typename T, typename ... Ts>
    auto sum_helper(Dummy d, T const &v, Ts const &...params)
            -> decltype(v + sum_helper(d, params...)) {
        return v + sum_helper(d, params...);
    }

    template<typename... P>
    auto sum( P const &...p )
            -> decltype( sum_helper( Dummy{}, p... ) {
        return sum_helper( Dummy{}, p... );
    }
}
using sum_impl::sum;

这篇关于可变模板的声明点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆