C++ noexcept声明更改模板推导

piy*_*iyo 8 c++ templates noexcept

我正在修补有效现代C++第91页上的例子,我遇到了一个似乎很奇怪的问题.这段代码

template<typename C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) {
    std::cout << "container version" << std::endl;
}

template<>
void doStuff<int>(int& x, int& y) noexcept {
    std::cout << "int version" << std::endl;
}

int main() {
    vector<int> v1 = {1, 2, 3};
    vector<int> v2 = {4, 5, 6};
    int x = 5;
    int y = 6;
    doStuff(x, y);
    doStuff(v1, v2);
}
Run Code Online (Sandbox Code Playgroud)

给我一个错误

错误:请求'a'中的成员'front',这是非类型'int'void doStuff(C&a,C&b)noexcept(noexcept(doStuff(a.front(),b.front()) )){

因此,似乎正在调用doStuff的顶级版本,即使a.front()和b.front()应该返回对int的引用.如果我从代码中删除所有noexcept声明,我得到预期的输出.

这是与gcc 5.4.

我究竟做错了什么?

谢谢

Bar*_*rry 7

问题是,当此名称查找时:

template<typename C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) {
//                                         ^^^^^^^
Run Code Online (Sandbox Code Playgroud)

只会找到一个doStuff():你的功能模板.专业化尚未宣布,因此不予考虑.

首先要做的是简单地避免专业化.他们很尴尬.但真正的解决方法是坚持使用额外的空类型,仅用于依赖于参数的查找目的.这将为noexcept查找添加一个依赖名称,这将延迟调用直到实例化:

namespace N {
    struct adl { };

    void doStuff(adl, int& , int& ) noexcept {
        std::cout << "int version" << std::endl;
    }

    template<typename C>
    void doStuff(adl, C& a, C& b) noexcept(noexcept(doStuff(adl{}, a.front(), b.front()))) {
        std::cout << "container version" << std::endl;
    }
}

template <class C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(N::adl{}, a, b)))
{
    doStuff(N::adl{}, a, b);
}
Run Code Online (Sandbox Code Playgroud)