2017-05-03 51 views
8

我有一个问题,这是非常相似this之一。不一致有条件noexcept和过载

总之,我有一个magic方法,这是noexcept如果另一种方法是noexcept

奇怪的是,这种“的另一种方法”,有两个过载,并且编译器选择了第二超负荷确定magicnoexcept -ness。

然而,当magic被称为后来,第一超载被调用,但noexcept -ness的magic保持不变!

这里是wandbox link

从我的理解:

  1. noexcept(magic(dummy2{}))电话
  2. noexcept(noexcept(adl_caller(...))其回落到
  3. adl_caller(..., priority_tag<0>) noexcept因为user_method(dummy2)不受此时编译器知道。

不够公平,但是,user_method(dummy2)如何调用3行以上? 这是标准打算的吗?

很抱歉,如果我不够清晰。

#include <iostream> 

template <unsigned N> struct priority_tag : priority_tag<N - 1> {}; 
template <> struct priority_tag<0> {}; 

template <typename T> 
auto adl_caller(T t, priority_tag<1>) noexcept(noexcept(user_method(t))) 
    -> decltype(user_method(t)) { 
    std::cout << "first adl_caller overload" << std::endl; 
    user_method(t); 
} 

// tricky noexcept ... 
template <typename T> void adl_caller(T, priority_tag<0>) noexcept { 
    std::cout << "second adl_caller overload" << std::endl; 
} 

template <typename T> 
void magic(T t) noexcept(noexcept(adl_caller(t, priority_tag<1>{}))) { 
    adl_caller(t, priority_tag<1>{}); 
} 

struct dummy {}; 
struct dummy2 {}; 

// un-commenting this line makes the above call to cout print '0' 
// void user_method(dummy2); 

void user_method(dummy) 
{ 
    // user_method(dummy2) is declared after this point 
    // this line prints '1', since magic falls back to the second adl_caller overload 
    std::cout << "noexcept?: " << noexcept(magic(dummy2{})) << std::endl; 
    std::cout << "dummy method called" << std::endl; 
    // however, the first adl_caller overload is called here ... 
    magic(dummy2{}); 
} 

void user_method(dummy2) 
{ 
    std::cout << "dummy2 method called" << std::endl; 
} 

int main() 
{ 
    magic(dummy{}); 
} 

回答

6

[temp.point]/8

一种用于函数模板特[...]可 有一个翻译单元内的实例化的多个点,并在除上述实例化的点 ,对于具有 翻译单元内实例化的一个点的任何 这样专业化,翻译单元的端部也被认为是 点实例化。 [...]如果实例 的两个不同的点得到模板特根据 一个定义规则不同的含义,是形成不良的程序,不需要诊断 。

比较[temp.dep.candidate]

对于函数调用,其中后缀表达式是从属 名,候选功能使用通常的查找规则 实测值([basic.lookup.unqual ],[basic.lookup.argdep])不同之处在于:

  • 对于使用不合格的名称查找所述查找的一部分,唯一的乐趣找到来自模板定义上下文的ction声明。

  • 对于使用相关联的命名空间的查找的部分([basic.lookup.argdep])中,只有在任一 模板定义上下文或模板实例上下文 发现函数声明被发现。

如果呼叫会形成不良或会找到更好的比赛不得不考虑所有的功能 声明与 这些命名空间中引入了外部链接的所有翻译单元,而不仅仅是考虑相关的命名空间内查找这些声明在模板定义和模板实例化上下文中发现 ,然后 程序具有未定义的行为。

+0

我想我理解这些段落的某些部分,但它们对我来说有点太模糊。在我的示例中,我只有一个TU并且没有外部链接功能,与代码I链接的最后一段如何?如果我理解正确,'魔术'方法与第一段相关,但我有一些问题需要理解确切的原因。尽管如此,非常感谢标准摘录 – Dante