我正在尝试创建一个默认显式的转换运算符,除了一些指定的类。
更准确地说,我有一个相对简单的类模板,其实例应该可以转换为其他类型(为简单起见,整个问题中的int
)。但是,我希望默认情况下此转换是显式的,但仍然允许它为另一个类隐式,即作为模板参数传递的类。没有这最后一部分,这就是它的样子:
template<typename T>
class A {
public:
A(int i) : i(i) {}
explicit operator int() const {
return i;
}
private:
int i;
};
现在,我希望能够在A a(2); int i = a;
(它应该是一个类)的方法中编写类似T
的东西。
我的第一个想法是利用朋友声明并声明转换运算符的私有重载。但是,不允许仅基于explicit
进行重载。所以我尝试使用const
代替它,它工作:
template<typename T>
class A {
public:
A(int i) : i(i) {}
explicit operator int() { // Public non-const
return i;
}
private:
int i;
operator int() const { // Private const
return i;
}
friend T;
};
......直到没有。这只适用于使用非常量A
s,虽然我不打算使用const A
s,但我仍然希望它适用于所有情况。请注意,如果公共重载是const
而私有不是,则仅使用const A
s。
Here is a demo显示它工作或不工作的情况。
我曾经想过使用volatile
(demo),虽然它使它更好,但它仍然会导致同样的问题:它只在使用非易失性A
s时才有效。
有没有更好的方法呢?更一般地说,有没有办法在第一句话中解决问题?
显然没有令人满意的解决方案。 volatile
选项似乎是最实用的,虽然它与volatile A
s不太一致,但额外的const_cast
解决了这个问题。
template<typename T>
class A {
public:
A(int i) : i(i) {}
explicit operator int() const {
return i;
}
private:
int i;
operator int() const volatile {
return static_cast<int>(const_cast<A const&>(*this));
// or just
// return i;
}
friend T;
};
正如Sneftel在评论中所述,访问权限倾向于以拉取(using
)而非推送为基础授予。这可能就是为什么语言不提供改变转换语义的方法,具体取决于执行转换的类或块。