与条件 noexcept 和重载不一致
Inconsistencies with conditional noexcept and overloads
我有一个与 非常相似的问题。
简而言之,我有一个magic
方法,如果另一个方法是noexcept
,它就是noexcept
。
奇怪的是这个"another method"有两个重载,编译器选择第二个重载来确定magic
noexcept
-尼斯.
然而,当稍后调用 magic
时,会调用 first 重载,但 magic
的 noexcept
-ness 仍然存在一样!
这是魔杖盒link
据我了解:
noexcept(magic(dummy2{}))
调用
noexcept(noexcept(adl_caller(...))
回到
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{});
}
A specialization for a function template [...] may
have multiple points of instantiations within a translation unit, and
in addition to the points of instantiation described above, for any
such specialization that has a point of instantiation within the
translation unit, the end of the translation unit is also considered a
point of instantiation. [...] If two different points of instantiation
give a template specialization different meanings according to the
one-definition rule, the program is ill-formed, no diagnostic
required.
For a function call where the postfix-expression is a dependent
name, the candidate functions are found using the usual lookup rules
([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup, only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations found in either
the template definition context or the template instantiation context
are found.
If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function
declarations with external linkage introduced in those namespaces in
all translation units, not just considering those declarations found
in the template definition and template instantiation contexts, then
the program has undefined behavior.
我有一个与
简而言之,我有一个magic
方法,如果另一个方法是noexcept
,它就是noexcept
。
奇怪的是这个"another method"有两个重载,编译器选择第二个重载来确定magic
noexcept
-尼斯.
然而,当稍后调用 magic
时,会调用 first 重载,但 magic
的 noexcept
-ness 仍然存在一样!
这是魔杖盒link
据我了解:
noexcept(magic(dummy2{}))
调用noexcept(noexcept(adl_caller(...))
回到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{});
}
A specialization for a function template [...] may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation. [...] If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup, only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations found in either the template definition context or the template instantiation context are found.
If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.