我不能阻止编译,这是一种不受欢迎的C风格演员。不受欢迎的强制转换执行从某个类的对象到其他类的非const引用的C样式强制转换。这些课程是无关的。同时我喜欢支持从同一个类的对象到const引用的C样式转换。我提供了一个公共转换运算符来支持理想的转换。在这种情况下,似乎不可能防止不良铸件 转换为非const引用无法构建(" Sandbox :: B :: operator Sandbox :: A&()"(在第30行声明)无法访问* ),不幸的是转换为const引用要么失败(错误:来自&#34的多个转换函数; Sandbox :: B"到" const Sandbox :: A&# 34;适用: function" Sandbox :: B :: operator const Sandbox :: A&()" function" Sandbox :: B :: operator Sandbox :: A&()" ):
#include <iostream>
#include <string>
#include <cstdlib>
namespace Sandbox {
class A {
public:
A (int i) : _x (i) { }
private:
int _x;
};
class B {
public:
B (const char* m) : _m (m), _a (std::atoi (m)) { }
/*
* This one shall be supported.
*/
operator const A& () {
return _a;
}
private:
/*
* This one shall be not supported.
* If this one is disabled both desired and undesired conversions pass the compilation.
*/
operator A& ();
const std::string _m;
const A _a;
};
}
int main () {
Sandbox::A a (1973);
Sandbox::B b ("1984");
/*
* This is the undesirable cast and it shall fail to compile.
*/
(Sandbox::A&)b;
/*
* This is the desirable cast and it shall pass the compilation.
*/
(const Sandbox::A&)b;
return 0;
}
如果我禁用运营商operator A& ()
,则会构建所需和不需要的转化。
我正在使用gcc,icc和MSVC编译。 我无法控制客户端代码并阻止使用C风格的转换。
答案 0 :(得分:3)
这应该可以解决问题(在clang3.5上测试):
#include <iostream>
#include <string>
#include <cstdlib>
namespace Sandbox {
class A {
public:
A (int i) : _x (i) { }
void fun()
{
std::cout << "action" << std::endl;
}
private:
int _x;
};
class B {
public:
B (const char* m) : _m (m), _a (std::atoi (m)) { }
/*
* This one shall be supported.
*/
template<typename T, typename Enable = typename std::enable_if<std::is_same<T, A>::value, A>::type>
operator const T& ()
{
return _a;
}
/*
* This one shall be not supported.
* If this one is disabled both desired and undesired conversions pass the compilation.
*/
private:
template<typename T, typename Enable = typename std::enable_if<std::is_same<T, A>::value, A>::type>
operator T& ();
const std::string _m;
const A _a;
};
}
int main () {
Sandbox::A a (1973);
Sandbox::B b ("1984");
/*
* This is the undesirable cast and it shall fail to compile.
*/
(Sandbox::A&)b;
/*
* This is the desirable cast and it shall pass the compilation.
*/
(const Sandbox::A&)b;
return 0;
}
至于为什么你的版本没有做你想要的,它与C风格的演员规则有关:
遇到C风格的强制转换表达式时,编译器会尝试 以下转换表达式,按此顺序:
a)const_cast(表达式)
b)static_cast(表达式), 带扩展名:指针或对派生类的引用 另外允许转换为指针或引用明确的 基类(反之亦然),即使基类不可访问 (也就是说,此强制转换会忽略私有继承说明符)。相同 适用于将指向成员的指针指向指向成员的指针 明确的非虚拟基础
c)接下来是static_cast(带扩展名) 通过const_cast
d)reinterpret_cast(表达式)
E) reinterpret_cast后跟const_cast
第一个选择 满足各个铸造操作员的要求 选中,即使无法编译
免责声明:此解释主要基于猜测,有多个步骤和复杂的规则,所以我不确定一切是否真的有效,因为我认为我已经理解了但是在这里你去了。的
由于您投射到引用,reinterpret_cast
将始终基于其rules of type aliasing工作,因此使C-Style强制转换失败的唯一方法是对其进行static_cast
类型明确地产生错误。遗憾的是,转换规则似乎并未将用户定义的转换为const
类型视为比用户定义的转换为非cv限定类型更好的匹配,即使它们都处于同一级别static_cast
目标类型为const
限定。使用模板,SFINAE和参数推导开始并且使用从山龙中提取的一些魔术编译器粉末,它可以工作。 (是的,这一步对我来说也有点神秘)。