具有依赖类型的c ++ 11可变函数模板重载是否模棱两可? [英] Is a c++11 variadic function template overload with a dependent type ambiguous?

查看:46
本文介绍了具有依赖类型的c ++ 11可变函数模板重载是否模棱两可?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码是递归可变参数函数重载的教科书示例.在clang和GCC中,它都能干净地编译,并且 main 返回36(按预期):

The following code is a textbook example of a recursive variadic function overload. In both clang and GCC, it compiles cleanly, and main returns 36 (as expected):

template <typename T>
int add(T val)
{
    return val;
}

template <typename FirstTypeT, typename... RestT>
int add(FirstTypeT first_value, RestT... rest)
{
    return first_value + add<RestT...>(rest...);
}

int main(void)
{
    return add(12, 12, 12);
}

但是,这里有一些修改.它在模板定义中使用依赖类型,而不是直接使用template参数:

However, here is a slight modification. It uses a dependent type in the template definition instead of the template parameter directly:

struct Foo
{
    using SomeType = int;
};

template <typename T>
int add(typename T::SomeType val)
{
    return val;
}

template <typename FirstT, typename... RestT>
int add(typename FirstT::SomeType first_value, typename RestT::SomeType... rest)
{
    return first_value + add<RestT...>(rest...);
}

int main(void)
{
    return add<Foo, Foo, Foo>(12, 12, 12);
}

它可以使用GCC 5.2进行编译和运行,但是使用clang 3.8 失败:

It compiles and runs as intended using GCC 5.2, but fails using clang 3.8:

clang++ variadic.cpp -o var -std=c++11 -Wall
variadic.cpp:15:26: error: call to 'add' is ambiguous
    return first_value + add<RestT...>(rest...);
                         ^~~~~~~~~~~~~
variadic.cpp:15:26: note: in instantiation of function template specialization 'add<Foo, Foo>' requested here
    return first_value + add<RestT...>(rest...);
                         ^
variadic.cpp:20:12: note: in instantiation of function template specialization 'add<Foo, Foo, Foo>' requested here
    return add<Foo, Foo, Foo>(12, 12, 12);
           ^
variadic.cpp:7:5: note: candidate function [with T = Foo]
int add(typename T::SomeType val)
    ^
variadic.cpp:13:5: note: candidate function [with FirstT = Foo, RestT = <>]
int add(typename FirstT::SomeType first_value, typename RestT::SomeType... rest)
    ^
1 error generated.

我的问题是双重的.

  1. 像在 typename RestT :: SomeType ... 中一样,将参数解析类型运算符应用于包的每个成员是否真的有效?
  2. 相对于标准而言,clang正确吗,或者这是一个错误吗?第二个例子真的比第一个例子更含糊吗?(对于第一个示例,您似乎可以说单参数重载是模棱两可的,而第二个参数重载用 RestT =<> 实例化)
  1. Is it really a valid use of a parameter pack typename pattern to apply the scope resolution operator to each member of the pack as in typename RestT::SomeType... ?
  2. Is clang correct vis-à-vis the standard, or is this a bug? Is the second example really any more ambiguous than the first? (For the first example, it seems like you could say that the single argument overload is ambiguous with the the second instantiated with RestT = <>)

推荐答案

  1. 是的,很好.
  2. 目前的措辞很清楚:部分排序期间完全忽略了参数包,因为没有参数(

  1. Yes, that's fine.
  2. Current wording is quite clear on this: The parameter pack is completely ignored during partial ordering, because there are no arguments for it ([temp.deduct.partial]/(3.1)). [temp.func.order]/5 also gives a very on point example, even with deducible template arguments - indicating that your first example is also ambiguous:

[注意:由于调用上下文中的部分排序仅考虑存在显式调用参数的参数,因此某些参数将被忽略(即,函数参数包,具有默认参数的参数,和省略号参数).[...] [示例:

[ Note: Since partial ordering in a call context considers only parameters for which there are explicit call arguments, some parameters are ignored (namely, function parameter packs, parameters with default arguments, and ellipsis parameters). [...] [ Example:

template<class T, class... U> void f(T, U ...);  // #1
template<class T            > void f(T       );  // #2

void h(int i) {
  f(&i); // error: ambiguous
  // [...]
}

但是,这不是最佳选择.可变参数模板部分上有核心问题1395 订购:

However, this is not optimal. There is core issue 1395 on variadic template partial ordering:

CWG同意接受该示例,将其作为抢七决胜案处理,在参数包中优先使用省略的参数.

(问题1825 提供了更多内容两种编译器都在第一种情况下实现了此规则.只有GCC才做第二个(即可以认为是领先了半步).

(Issue 1825 gives a more refined strategy.) Both compilers implement this rule for the first case; Only GCC does for the second one (i.e. can be considered half a step ahead).

这篇关于具有依赖类型的c ++ 11可变函数模板重载是否模棱两可?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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