C++ 基于类型特征的特殊化cast算子
这是我上一篇文章的后续文章 我有一个类,它对任何东西都有强制转换操作符。在C++17之前的环境中,这会导致在执行初始化时无法选择适当的构造函数重载的错误。我想通过为某些类型显式标记cast操作符来调整行为。但是,我找不到这样做的方法 这里是一个人工示例:我希望对整数类型使用隐式强制转换运算符,对所有其他类型使用显式强制转换运算符 这不起作用,因为我们无法确定您的表达式类型为typename std::enable\U if::value,U>::type: 我不能声明种类模板运算符U的函数;并且部分地专门化它,因为部分函数专门化是不允许的,并且在我看来,创建一个helper类似乎是一种过激的行为 如何根据要强制转换的类型的某些特征声明强制转换运算符C++ 基于类型特征的特殊化cast算子,c++,casting,template-meta-programming,sfinae,C++,Casting,Template Meta Programming,Sfinae,这是我上一篇文章的后续文章 我有一个类,它对任何东西都有强制转换操作符。在C++17之前的环境中,这会导致在执行初始化时无法选择适当的构造函数重载的错误。我想通过为某些类型显式标记cast操作符来调整行为。但是,我找不到这样做的方法 这里是一个人工示例:我希望对整数类型使用隐式强制转换运算符,对所有其他类型使用显式强制转换运算符 这不起作用,因为我们无法确定您的表达式类型为typename std::enable\U if::value,U>::type: 我不能声明种类模板运算符U的函数;并且
我需要一个C++11解决方案,就像在C++17中一样,我上一个问题中的问题已经存在。b试试这个。只需去掉显式操作符上的约束,因为它覆盖了第一个操作符没有覆盖的所有情况 例如:
感谢@Jodocus为整型类型启用显式转换。您可以将这些运算符的定义移动到基类。此方法允许对隐式运算符和显式运算符施加约束:
#include <type_traits>
#include <iostream>
template<typename TDerived> class
t_ImplicitlyConvertableToAnything
{
public: template
<
typename TTarget
, typename TEnabled = typename ::std::enable_if_t<::std::is_integral<TTarget>::value>
>
operator TTarget(void) const
{
auto const & self{static_cast<const TDerived &>(*this)};
return(self.template CheckedConversion_To_Integral<TTarget>());
}
};
template<typename TDerived> class
t_ExplicitlyConvertableToAnything
{
public: template
<
typename TTarget
, typename TEnabled = typename ::std::enable_if_t<!::std::is_integral<TTarget>::value>
> explicit
operator TTarget(void) const
{
auto const & self{static_cast<const TDerived &>(*this)};
return(self.template CheckedConversion_To_NonIntegral<TTarget>());
}
};
class
t_ConvertableToAnything
: public t_ImplicitlyConvertableToAnything<t_ConvertableToAnything>
, public t_ExplicitlyConvertableToAnything<t_ConvertableToAnything>
{
public: template<typename TTarget> decltype(auto)
CheckedConversion_To_Integral(void) const
{
return(static_cast<TTarget>(1));
}
public: template<typename TTarget> decltype(auto)
CheckedConversion_To_NonIntegral(void) const
{
return(static_cast<TTarget>(3.14));
}
};
int main()
{
t_ConvertableToAnything c;
::std::cout << ([](int x){return(x);})(c) << ::std::endl;
::std::cout << static_cast<float>(c) << ::std::endl;
return(0);
}
您可以使用非类型模板参数来避免无法重载的问题:
#include <iostream>
#include <type_traits>
struct A { };
struct B { };
struct C {
template <typename U,
typename std::enable_if<std::is_integral<U>::value>::type* = nullptr>
explicit operator U() const {
return 1;
}
template<typename U,
typename std::enable_if<std::is_same<U, A>::value>::type* = nullptr>
explicit operator U() const {
return A{ };
}
template<typename U,
typename std::enable_if<std::is_same<U, B>::value>::type* = nullptr>
explicit operator U() const {
return B{ };
}
};
int main() {
C c;
long y = static_cast<int>(c);
B b = static_cast<B>(c);
A a = static_cast<A>(c);
}
您可以使用带有伪模板参数的技巧重载cast操作符以消除歧义
struct C {
template<typename U,
typename = typename enable_if<is_integral<U>::value, U>::type,
int = 0> // <== hete
operator U() const {
return 1;
}
template<typename U,
typename = typename enable_if<!is_integral<U>::value, U>::type,
char = 0> // <== and here
explicit operator U() const {
return 1.5;
}
};
由于模板签名现在有所不同,因此没有歧义。希望您不介意,我冒昧地改进了无水平滚动的格式,并删除了enable_(如果没有)的无用默认参数。我很感激。非常感谢。添加typename std::enable_if::value>::type*=nullptr作为显式运算符重载的第二个模板参数将使程序支持不必要的显式强制转换s.t.int z=static_castc;现在,这将是一个模棱两可的调用,但是imho应该始终允许显式地写出强制转换。@Jodocus我同意应该支持这些。我到家后会看的,不过如果你确定它可以编译并工作的话,请随意修改。谢谢你的意见。这很有趣。
#include <type_traits>
#include <iostream>
template<typename TDerived> class
t_ImplicitlyConvertableToAnything
{
public: template
<
typename TTarget
, typename TEnabled = typename ::std::enable_if_t<::std::is_integral<TTarget>::value>
>
operator TTarget(void) const
{
auto const & self{static_cast<const TDerived &>(*this)};
return(self.template CheckedConversion_To_Integral<TTarget>());
}
};
template<typename TDerived> class
t_ExplicitlyConvertableToAnything
{
public: template
<
typename TTarget
, typename TEnabled = typename ::std::enable_if_t<!::std::is_integral<TTarget>::value>
> explicit
operator TTarget(void) const
{
auto const & self{static_cast<const TDerived &>(*this)};
return(self.template CheckedConversion_To_NonIntegral<TTarget>());
}
};
class
t_ConvertableToAnything
: public t_ImplicitlyConvertableToAnything<t_ConvertableToAnything>
, public t_ExplicitlyConvertableToAnything<t_ConvertableToAnything>
{
public: template<typename TTarget> decltype(auto)
CheckedConversion_To_Integral(void) const
{
return(static_cast<TTarget>(1));
}
public: template<typename TTarget> decltype(auto)
CheckedConversion_To_NonIntegral(void) const
{
return(static_cast<TTarget>(3.14));
}
};
int main()
{
t_ConvertableToAnything c;
::std::cout << ([](int x){return(x);})(c) << ::std::endl;
::std::cout << static_cast<float>(c) << ::std::endl;
return(0);
}
#include <iostream>
#include <type_traits>
struct A { };
struct B { };
struct C {
template <typename U,
typename std::enable_if<std::is_integral<U>::value>::type* = nullptr>
explicit operator U() const {
return 1;
}
template<typename U,
typename std::enable_if<std::is_same<U, A>::value>::type* = nullptr>
explicit operator U() const {
return A{ };
}
template<typename U,
typename std::enable_if<std::is_same<U, B>::value>::type* = nullptr>
explicit operator U() const {
return B{ };
}
};
int main() {
C c;
long y = static_cast<int>(c);
B b = static_cast<B>(c);
A a = static_cast<A>(c);
}
struct C {
template<typename U,
typename = typename enable_if<is_integral<U>::value, U>::type,
int = 0> // <== hete
operator U() const {
return 1;
}
template<typename U,
typename = typename enable_if<!is_integral<U>::value, U>::type,
char = 0> // <== and here
explicit operator U() const {
return 1.5;
}
};