"explicit" 和 "implicit" operator () 调用的区别
Difference between "explicit" and "implicit" invocation of operator ()
标准中是否有一个条款描述从基 classes 调用 operator ()
的方法之间的以下区别?
#include <iostream>
#include <type_traits>
#include <cstdlib>
#include <cassert>
template< typename visitor, typename ...visitors >
struct composite_visitor
: std::decay_t< visitor >
, composite_visitor< visitors... >
{
//using std::decay_t< visitor >::operator ();
//using composite_visitor< visitors... >::operator ();
composite_visitor(visitor && _visitor, visitors &&... _visitors)
: std::decay_t< visitor >(std::forward< visitor >(_visitor))
, composite_visitor< visitors... >{std::forward< visitors >(_visitors)...}
{ ; }
};
template< typename visitor >
struct composite_visitor< visitor >
: std::decay_t< visitor >
{
//using std::decay_t< visitor >::operator ();
composite_visitor(visitor && _visitor)
: std::decay_t< visitor >(std::forward< visitor >(_visitor))
{ ; }
};
template< typename visitor, typename ...visitors >
composite_visitor< visitor, visitors... >
compose_visitors(visitor && _visitor, visitors &&... _visitors)
{
return {std::forward< visitor >(_visitor), std::forward< visitors >(_visitors)...};
}
int
main()
{
struct A {};
struct B {};
#if 1
struct { int operator () (A) { return 1; } } x;
struct { int operator () (B) { return 2; } } y;
auto xy = compose_visitors(x, y);
#else
auto xy = compose_visitors([] (A) { return 1; }, [] (B) { return 2; });
#endif
// "implicit":
assert(xy(A{}) == 1);
assert(xy(B{}) == 2);
// "explicit":
assert(xy.operator () (A{}) == 1); // error: member 'operator()' found in multiple base classes of different types
assert(xy.operator () (B{}) == 2);
return EXIT_SUCCESS;
}
"Implicit" 调用可以正常编译,但 "explicit" 却不行。为什么会这样?
compose_visitors
通过构造一个从所有参数派生的 class 将参数组合成单个 class。
取消对 using
指令的注释可消除硬错误。清楚了。
lambda 函数和仿函数的行为相同。
编译器是 clang 3.6.
"implicit" 调用也是格式错误的。事实上,GCC rejects it,所以它似乎是 Clang 中的一个错误。
标准(N4140,[over.call]/1)明确表示
a call x(arg1,...)
is interpreted as x.operator()(arg1, ...)
for a class object x
of type T
if T::operator()(T1, T2, T3)
exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3.3).
所以这两个调用的行为必须相同。
更新:这是 Clang 中的 known issue。
标准中是否有一个条款描述从基 classes 调用 operator ()
的方法之间的以下区别?
#include <iostream>
#include <type_traits>
#include <cstdlib>
#include <cassert>
template< typename visitor, typename ...visitors >
struct composite_visitor
: std::decay_t< visitor >
, composite_visitor< visitors... >
{
//using std::decay_t< visitor >::operator ();
//using composite_visitor< visitors... >::operator ();
composite_visitor(visitor && _visitor, visitors &&... _visitors)
: std::decay_t< visitor >(std::forward< visitor >(_visitor))
, composite_visitor< visitors... >{std::forward< visitors >(_visitors)...}
{ ; }
};
template< typename visitor >
struct composite_visitor< visitor >
: std::decay_t< visitor >
{
//using std::decay_t< visitor >::operator ();
composite_visitor(visitor && _visitor)
: std::decay_t< visitor >(std::forward< visitor >(_visitor))
{ ; }
};
template< typename visitor, typename ...visitors >
composite_visitor< visitor, visitors... >
compose_visitors(visitor && _visitor, visitors &&... _visitors)
{
return {std::forward< visitor >(_visitor), std::forward< visitors >(_visitors)...};
}
int
main()
{
struct A {};
struct B {};
#if 1
struct { int operator () (A) { return 1; } } x;
struct { int operator () (B) { return 2; } } y;
auto xy = compose_visitors(x, y);
#else
auto xy = compose_visitors([] (A) { return 1; }, [] (B) { return 2; });
#endif
// "implicit":
assert(xy(A{}) == 1);
assert(xy(B{}) == 2);
// "explicit":
assert(xy.operator () (A{}) == 1); // error: member 'operator()' found in multiple base classes of different types
assert(xy.operator () (B{}) == 2);
return EXIT_SUCCESS;
}
"Implicit" 调用可以正常编译,但 "explicit" 却不行。为什么会这样?
compose_visitors
通过构造一个从所有参数派生的 class 将参数组合成单个 class。
取消对 using
指令的注释可消除硬错误。清楚了。
lambda 函数和仿函数的行为相同。
编译器是 clang 3.6.
"implicit" 调用也是格式错误的。事实上,GCC rejects it,所以它似乎是 Clang 中的一个错误。
标准(N4140,[over.call]/1)明确表示
a call
x(arg1,...)
is interpreted asx.operator()(arg1, ...)
for a class objectx
of typeT
ifT::operator()(T1, T2, T3)
exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3.3).
所以这两个调用的行为必须相同。
更新:这是 Clang 中的 known issue。