首页 文章

函数参数包的模板参数推导后跟其他参数

提问于
浏览
7

f1f2 的演绎是否形成错误?

template<class... T, class U>
void f1(T..., U){}

template<class... T>
void f2(T..., int){}

int main()
{
    f1(1);
    f2(1);
    return 0;
}

g接受两者,clang只接受 f2 ,而msvc拒绝这两者 .

相关标准措辞:

[temp.deduct.call]

当函数参数包出现在非推导的上下文([temp.deduct.type])中时,永远不会推导出该参数包的类型 .

[temp.deduct.type]p5

非推导的上下文是:一个函数参数包,它不会出现在参数声明列表的末尾 .

所以似乎MSVC拒绝两者都是正确的?

这是否意味着即使您明确指定模板args,模板的任何实例化都将是格式错误的?

f1<int>(1, 2); // ill-formed?
f2<int>(1, 2); // ill-formed?

如果是这样的话,为什么要在第一时间允许这样的声明呢?

2 回答

  • 2

    这个特定问题DR1388有一个DR . 显然,GCC和CLANG似乎还没有实现它CLANG DR1388 .

    这是否意味着即使您明确指定模板args,模板的任何实例化都将是格式错误的? f1 <int>(1,2); //格格不入?
    f2 <int>(1,2); //格格不入?
    如果是这样的话,为什么要在第一时间允许这样的声明呢?

    否如果您明确指定模板参数,则不会发生扣减,因此上面显示的代码是合法的 .

  • 0

    我发现很难得到一个明确的答案 . 我可以说, f1(1) 应该是 rejectedf2(1) 应该是 accepted .

    那说:

    • clang -5.0接受两者

    • g -6接受两者

    • EDG 4.14拒绝两者


    正如您所指出的,未在列表末尾出现的函数参数包是非推导的上下文([temp.deduct.type] p5):

    非推导的上下文是:...函数参数包,它不会出现在参数声明列表的末尾 .

    和[temp.deduct.call] p1(通过CWG 1388修订)澄清了从不推断出这样的参数包 .

    当函数参数包出现在非推导的上下文中时,永远不会推导出该参数包的类型 .

    另外,[temp.arg.explicit] p3指定:

    未以其他方式推导出的尾随模板参数包(14.5.3)将被推导为空的模板参数序列 .

    因此,考虑到 f2(1) 调用:包T是一个尾随模板参数包(虽然它不是一个尾随的函数参数包),因此它推断为空包并且该调用有效 .

    但是,对于 f1(1) ,包T也不是尾随模板参数包,因为它后跟 U ,因此不会假定每个[temp.arg.explicit] p3为空包 . 因此,由于无法推断模板参数包T对 f1(1) 的调用,它不应参与重载解析,并且调用应该失败 .


    请注意,在其他讨论中提出了几个类似的问题/示例,但它们都有微妙的不同:

    • CWG 1388CWG 1399的示例代码中的 f(0) 调用有效,因为有问题的包是一个尾随模板参数包,因此它属于我上面提到的情况 . 以下是CWG 1399的代码:

    template <class ... T>
    void f(T ...,int,T ...){}

    int main(){
    F(0); // 好
    ˚F<int>的(0,0,0); // 好
    F(0,0,0); //错误
    }

    • LLVM bug 21774讨论中的示例代码类似于CWG 1399示例,该包是一个尾随模板参数包 . 同样对于question .

    • CWG 2055,未解决,涉及类似的测试用例 . 无论什么时候解决,它的解决方案都可能会对这个问题中的例子的正确行为有所了解 . 以下是CWG 2055中提到的问题:

    目前尚不清楚[标准的当前措辞]是否允许例如:template <typename ... T> void f(typename T :: type ...){
    }

    int main(){
    ˚F<>();
    }

相关问题