C++ C++;函数重载中的不明确调用 只是一个好奇心(学术问题:P),考虑下面的代码: struct Y {}; class PassConstY { public: PassConstY(const Y& y) {} }; class PassY { public: PassY(Y& y) {} }; void z(PassConstY y) {} void z(PassY y) {} void h(const Y& y) {} void h(Y& y) {} Y y; const Y cy; h(cy); //OK h(y); //OK z(cy); //OK z(y); //Ambiguity
问题:是否可以编写C++ C++;函数重载中的不明确调用 只是一个好奇心(学术问题:P),考虑下面的代码: struct Y {}; class PassConstY { public: PassConstY(const Y& y) {} }; class PassY { public: PassY(Y& y) {} }; void z(PassConstY y) {} void z(PassY y) {} void h(const Y& y) {} void h(Y& y) {} Y y; const Y cy; h(cy); //OK h(y); //OK z(cy); //OK z(y); //Ambiguity,c++,C++,问题:是否可以编写PassY和PassConstYs.t z和h遵循完全相同的重载规则 如果我删除可变Y的z和h定义,代码仍会编译(即,我也可以调用可变版本的z和h) 我的猜测是否定的,从某种意义上说,我设法只从一个常量Y构造了PassConstY(而不是一个可变Y),这消除了歧义,但第2点注定要失败 澄清: PassY和PassConstY可以根据您的喜好定义(但必须是类,可以是模板),但z和h的定义必须保持不变 当仅定义z和h的“const”版本时,必须编译以下代码: const Y y;
PassY
和PassConstY
s.t
z
和h
遵循完全相同的重载规则Y
的z
和h
定义,代码仍会编译(即,我也可以调用可变版本的z
和h
)常量Y
构造了PassConstY
(而不是一个可变Y
),这消除了歧义,但第2点注定要失败
澄清: PassY和PassConstY可以根据您的喜好定义(但必须是类,可以是模板),但z和h的定义必须保持不变 当仅定义z和h的“const”版本时,必须编译以下代码:
const Y y;
z(y); //Calls z(PassConstY y)
h(y); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassConstY y)
h(x); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassY y)
h(x); //Calls h(Y& y)
const Y y;
z(y); //Calls z(PassConstY y)
h(y); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassY y)
h(x); //Calls h(Y& y)
当仅定义z和h的“可变”版本时,必须编译以下代码:
const Y y;
z(y); //Calls z(PassConstY y)
h(y); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassConstY y)
h(x); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassY y)
h(x); //Calls h(Y& y)
const Y y;
z(y); //Calls z(PassConstY y)
h(y); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassY y)
h(x); //Calls h(Y& y)
定义h和z的两个版本时,必须编译以下代码:
const Y y;
z(y); //Calls z(PassConstY y)
h(y); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassConstY y)
h(x); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassY y)
h(x); //Calls h(Y& y)
const Y y;
z(y); //Calls z(PassConstY y)
h(y); //Calls h(const Y& y)
Y x;
z(x); //Calls z(PassY y)
h(x); //Calls h(Y& y)
对不起,如果原来的问题不够清楚
动机(这是我在Stackoverflow上的另一个问题): 考虑到下面评论中的“禁用r值绑定”,我想提出一个模板类Ref(将其视为智能引用),我可以在编写函数定义时使用它,如:
struct X {};
void f(Ref<X> x) {} //Instead of void f(X& x)
void f(Ref<const X> x) {} //Instead of void f(const X& x)
struct X{};
void f(Ref x){}//而不是void f(x&x)
void f(Ref x){}//而不是void f(const x&x)
因此,在调用函数f时(就重载解析/转换而言),我得到了与普通引用版本相同的行为,但Ref从未绑定到右值
[对于这部分,需要C++0X]原因是:
- 如果SCS 1将引用绑定到常量,SCS 2将引用绑定到非常量,则SCS 1优于SCS 2
- UCS 1优于UCS 2,当且仅当两者使用相同的转换函数或构造函数时李>
h
,如果两个函数都是可行的候选函数(第二次调用),则第一个项目符号将确定胜利者。对于z
,如果两个函数都是可行的候选函数(第二次调用),则没有比其他UCS更好的UCS,因为两个UCS使用不同的构造函数
请注意,UCS定义为
- 一个SCS(如果使用构造函数,将参数转换为构造函数的参数类型;对于转换运算符函数,将参数转换为
)TypeOf(*this)&
- 调用用户定义的转换(构造函数或转换运算符函数)
- 另一个SCS(将转换结果转换为最终目标类型)
h
函数的UCS不存在第一个SCS,因此它不是可行的候选者。但是,对h
的第二次调用并非如此,因此会导致上述歧义
我缩短了一些术语: UCS:用户定义的转换顺序
标准转换序列
我的猜测是否定的,从某种意义上说,我设法让PassConstY仅从一个consty(而不是一个可变的Y)构造,这消除了歧义,但第2点注定要失败 如果我理解正确的话,你的这种怀疑是不对的。使用当前的定义,您可以删除
h
和z
的可变版本,您的代码将可以正常编译。有一个SCS用于Y
到const Y&
当然,您可以将PassY和PassConstY重写为
typedef Y &PassY;
typedef Y const& PassConstY;
除此之外,我不知道你说“重写”是什么意思。如果您只想更改类主体,那么重载解析肯定会有所不同 我不确定这是否对您有帮助,但您可以为使用模板的
z
编写包装器:
template <typename T>
struct TypeFor {
typedef PassY type;
};
template <typename T>
struct TypeFor<const T> {
typedef PassConstY type;
};
template <typename T>
void wrap_z(T& y) { z(static_cast<typename TypeFor<T>::type>(y)); }
模板
结构类型{
typedef-PassY型;
};
模板
结构类型{
typedef PassConstY类型;
};
模板
空包z(T&y){z(静态cast(y));}
现在,根据调用参数类型,T
将变为Y
或const Y
,并将使用正确的显式转换
这使用了结构(而不是函数)可以部分特殊化的事实,我们在这里针对T
z(y)的不同常量所做的工作是不明确的,因为在这两者之间有一个隐式转换,它不知道是哪一个
如果对PassY和PassConstY使用显式构造函数,那么两个z都将失败
还可以使用隐式构造函数传递模板:
template< typename T >
class Pass
{
Pass( T& t ) {}
};
typedef Pass<Y> PassY;
typedef Pass<const Y> PassConstY;
模板
班级通行证
{
通过(T&T){}
};
typedef PassY;
typedef PassConstY;
我仍然不确定这是否能解决您的问题,但您也可以将z作为模板函数:
template< typename T> void z( Pass<T> t );
templatevoid z(通过T);
虽然在实际代码中,我会避免隐式转换并使用函数
template<typename T> Pass<T> pass(T& t) { return Pass<T>(t); }
模板传递(T&T){返回传递(T);}
以上是部分专业化,您还可以定义
template< typename T> void z( T& t) { z( pass(t) ); }
templatevoid z(T&T){z(pass(T));}
它应该可以工作。我想要实现的是编译代码(对于PassY和PassConstY的某些定义,它们的构造函数可以根据您的喜好进行更改),这两种情况都是:1)仅存在h和z的const版本,2)存在h和z的const和可变版本。但是PassY和PassConstY必须是类(而不是typedef),因为我必须对它们执行其他操作(禁用与rvalues:P的绑定)。谢谢你