【问题标题】:Inconsistencies with conditional noexcept and overloads与条件 noexcept 和重载不一致
【发布时间】:2017-10-01 12:53:14
【问题描述】:

我有一个与this 非常相似的问题。

简而言之,我有一个magic 方法,如果另一个方法是noexcept,它就是noexcept。

奇怪的是,这个“另一种方法”有两个重载,编译器选择第二个重载来判断magicnoexcept-ness。

但是,当稍后调用 magic 时,会调用 first 重载,但 magic 的 noexcept-ness 保持不变!

这是魔杖盒link

据我了解:

  1. noexcept(magic(dummy2{})) 来电
  2. noexcept(noexcept(adl_caller(...)) 回退到
  3. adl_caller(..., priority_tag<0>) noexceptsince 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{});
}

【问题讨论】:

    标签: c++ c++11 templates argument-dependent-lookup noexcept


    【解决方案1】:

    [temp.point]/8:

    函数模板的特化 [...] 可能 在翻译单元中有多个实例化点,并且 除了上述实例化点之外,对于任何 这种特殊化在 翻译单元,翻译单元的结尾也被认为是一个 实例化点。 [...] 如果两个不同的实例化点 根据模板特化赋予不同的含义 单定义规则,程序格式错误,无诊断 必填。

    比较[temp.dep.candidate]:

    对于 后缀表达式 是依赖的函数调用 名称,候选函数是使用通常的查找规则找到的 ([basic.lookup.unqual], [basic.lookup.argdep]) 除了:

    • 对于使用非限定名称查找的部分查找,只能找到来自模板定义上下文的函数声明。

    • 对于使用关联命名空间 ([basic.lookup.argdep]) 的查找部分,仅在两者中找到的函数声明 模板定义上下文或模板实例化上下文 找到了。

    如果调用格式不正确或找到更好的匹配,则相关命名空间中的查找将考虑所有函数 在这些名称空间中引入的具有外部链接的声明 所有翻译单元,而不仅仅是考虑找到的那些声明 在模板定义和模板实例化上下文中,然后 程序有未定义的行为。

    【讨论】:

    • 我想我理解了这些段落的某些部分,但它们对我来说有点太模糊了。我的示例中只有一个 TU,没有外部链接功能,最后一段与我链接的代码有什么关系?如果我理解正确,magic 方法与第一段相关联,但我很难掌握确切的原因。非常感谢标准摘录
    猜你喜欢
    • 1970-01-01
    • 2017-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-08
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多