为什么在这种情况下重载决议不明确?
Why is overload resolution is ambiguous in this case?
我编写这段代码是为了检查 class 类型是否具有 begin
函数。
struct foo //a simple type to check
{
int begin(){ return 0;}
};
struct Fallback
{
int begin(){ return 0;}
};
template<typename T>
struct HasfuncBegin : T,Fallback
{
typedef char one;
typedef int two;
template<typename X>
static one check(int (X::*)() = &HasfuncBegin<T>::begin);
template<typename X>
static two check(...);
enum :bool {yes = sizeof(check<T>())==1, no= !yes};
};
int main()
{
std::cout<< HasfuncBegin<foo>::yes;
return 0;
}
产生错误:
error: call of overloaded 'check()' is ambiguous
enum {yes = sizeof(check<T>())==1, no= !yes};
^
C:\XXX\main.cpp:24:16: note: candidate: static HasfuncBegin<T>::one HasfuncBegin<T>::check(int (X::*)()) [with X = foo; T = foo; HasfuncBegin<T>::one = char]
static one check(int (X::*)() = &HasfuncBegin<T>::begin);
^
C:\XXX\main.cpp:26:16: note: candidate: static HasfuncBegin<T>::two HasfuncBegin<T>::check(...) [with X = foo; T = foo; HasfuncBegin<T>::two = int]
static two check(...);
^
任何人都可以解释为什么调用不明确(即使首先检查带有签名 one check(int (X::*)() = &HasfuncBegin<T>::begin);
的函数具有要使用的默认参数)和还有如何使我的代码工作?
编辑:
所以这是最终的工作代码:
struct foo
{
int begin(){ return 0;}
};
struct Fallback
{
int begin(){ return 0;}
};
template<typename T, T ptr> struct dummy{};
template<typename T>
struct HasfuncBegin : T,Fallback
{
typedef char one;
typedef int two;
template<typename X>
static one check(dummy<int (X::*)(),&HasfuncBegin<X>::begin>*);
// even this won't work, so replace above statement with below commented one
// static one check(dummy<decltype(&HasfuncBegin<X>::begin),&HasfuncBegin<X>::begin>*);
template<typename X>
static two check(...);
enum {yes = sizeof(check<T>(0))==1, no= !yes};
};
产生歧义的原因是 check()
的两个(模板化)重载都是 check<T>()
的有效匹配项。您可能认为一个比另一个更有效,但语言规则是它们同样有效。
可变参数函数 (...
) 匹配零个或多个参数(即 check<T>()
)。具有默认值的单个参数的函数可以匹配 check<T>()
.
因此关于歧义的消息。
您实际上并没有描述您尝试使用此代码实现的目标(特别是 enum
的初始化),但不知何故期待我们能够解决您的尝试。让它编译的明显方法是删除其中一个重载。
但是,除非你描述你真正想要达到的目标,否则没有人能给你建议。像这样的阅读网站不会赋予人们读心术的能力。
调用不明确,因为重载选择是基于从调用参数到函数参数的转换序列。规则有点复杂,无法在此处完整解释,但请考虑以下两个示例:
void ex1(int) {} //v1
void ex1(...) {} //v2
void ex2(int = 1) {} //v1
void ex2(...) {} //v2
int main() {
ex1(1);
ex2();
}
ex1(1)
调用是 well-formed。有一个参数具有比 v2
更好的 v1
隐式转换序列(完全匹配与省略号转换)。
ex2()
调用是 ill-formed。没有用于比较转换序列的参数,并且可以在没有参数的情况下调用两个重载。这类似于您的代码。
看起来你被 C++03 困住了,所以这里有一个可能的解决方案,使用 this answer:
template<typename T>
struct HasfuncBegin {
typedef char yes[1];
typedef char no [2];
template <typename U, U> struct type_check;
template <typename _1> static yes &chk(type_check<int (T::*)(), &_1::begin > *);
template <typename > static no &chk(...);
static bool const value = sizeof(chk<T>(0)) == sizeof(yes);
};
我编写这段代码是为了检查 class 类型是否具有 begin
函数。
struct foo //a simple type to check
{
int begin(){ return 0;}
};
struct Fallback
{
int begin(){ return 0;}
};
template<typename T>
struct HasfuncBegin : T,Fallback
{
typedef char one;
typedef int two;
template<typename X>
static one check(int (X::*)() = &HasfuncBegin<T>::begin);
template<typename X>
static two check(...);
enum :bool {yes = sizeof(check<T>())==1, no= !yes};
};
int main()
{
std::cout<< HasfuncBegin<foo>::yes;
return 0;
}
产生错误:
error: call of overloaded 'check()' is ambiguous
enum {yes = sizeof(check<T>())==1, no= !yes};
^
C:\XXX\main.cpp:24:16: note: candidate: static HasfuncBegin<T>::one HasfuncBegin<T>::check(int (X::*)()) [with X = foo; T = foo; HasfuncBegin<T>::one = char]
static one check(int (X::*)() = &HasfuncBegin<T>::begin);
^
C:\XXX\main.cpp:26:16: note: candidate: static HasfuncBegin<T>::two HasfuncBegin<T>::check(...) [with X = foo; T = foo; HasfuncBegin<T>::two = int]
static two check(...);
^
任何人都可以解释为什么调用不明确(即使首先检查带有签名 one check(int (X::*)() = &HasfuncBegin<T>::begin);
的函数具有要使用的默认参数)和还有如何使我的代码工作?
编辑:
所以这是最终的工作代码:
struct foo
{
int begin(){ return 0;}
};
struct Fallback
{
int begin(){ return 0;}
};
template<typename T, T ptr> struct dummy{};
template<typename T>
struct HasfuncBegin : T,Fallback
{
typedef char one;
typedef int two;
template<typename X>
static one check(dummy<int (X::*)(),&HasfuncBegin<X>::begin>*);
// even this won't work, so replace above statement with below commented one
// static one check(dummy<decltype(&HasfuncBegin<X>::begin),&HasfuncBegin<X>::begin>*);
template<typename X>
static two check(...);
enum {yes = sizeof(check<T>(0))==1, no= !yes};
};
产生歧义的原因是 check()
的两个(模板化)重载都是 check<T>()
的有效匹配项。您可能认为一个比另一个更有效,但语言规则是它们同样有效。
可变参数函数 (...
) 匹配零个或多个参数(即 check<T>()
)。具有默认值的单个参数的函数可以匹配 check<T>()
.
因此关于歧义的消息。
您实际上并没有描述您尝试使用此代码实现的目标(特别是 enum
的初始化),但不知何故期待我们能够解决您的尝试。让它编译的明显方法是删除其中一个重载。
但是,除非你描述你真正想要达到的目标,否则没有人能给你建议。像这样的阅读网站不会赋予人们读心术的能力。
调用不明确,因为重载选择是基于从调用参数到函数参数的转换序列。规则有点复杂,无法在此处完整解释,但请考虑以下两个示例:
void ex1(int) {} //v1
void ex1(...) {} //v2
void ex2(int = 1) {} //v1
void ex2(...) {} //v2
int main() {
ex1(1);
ex2();
}
ex1(1)
调用是 well-formed。有一个参数具有比 v2
更好的 v1
隐式转换序列(完全匹配与省略号转换)。
ex2()
调用是 ill-formed。没有用于比较转换序列的参数,并且可以在没有参数的情况下调用两个重载。这类似于您的代码。
看起来你被 C++03 困住了,所以这里有一个可能的解决方案,使用 this answer:
template<typename T>
struct HasfuncBegin {
typedef char yes[1];
typedef char no [2];
template <typename U, U> struct type_check;
template <typename _1> static yes &chk(type_check<int (T::*)(), &_1::begin > *);
template <typename > static no &chk(...);
static bool const value = sizeof(chk<T>(0)) == sizeof(yes);
};