C++ 选择模板化操作符实现
假设我们在自定义类上有一个C++ 选择模板化操作符实现,c++,templates,C++,Templates,假设我们在自定义类上有一个操作符/: struct my_class { uint64_t value; } template<class T> constexpr T operator/(const my_class& a, const my_class& b) { return static_cast<T>(a.value) / static_cast<T>(b.value); } struct my_类{ uint64
操作符/
:
struct my_class {
uint64_t value;
}
template<class T>
constexpr T operator/(const my_class& a, const my_class& b)
{
return static_cast<T>(a.value) / static_cast<T>(b.value);
}
struct my_类{
uint64_t值;
}
模板
constexpr T运算符/(const my_class&a,const my_class&b)
{
返回静态转换(a值)/静态转换(b值);
}
如何选择
a/b
(其中a
和b
属于my_class
类型)以返回int
或double
,例如?要选择特定的运算符模板,必须将其作为函数调用:
auto result = operator/<double>(my_class{4}, my_class{2});
// result is 2.0
auto result=operator/(my_class{4},my_class{2});
//结果是2.0
要选择特定的操作员模板,必须将其作为函数调用:
auto result = operator/<double>(my_class{4}, my_class{2});
// result is 2.0
auto result=operator/(my_class{4},my_class{2});
//结果是2.0
您可以使用一些模板魔术和转换运算符。您可以首先为表达式定义一个简单的包装器:
struct DivideMyClass {
DivideMyClass(const MyClass& lhs_, const MyClass& rhs_) : lhs{lhs_}, rhs_{rhs} {}
template<typename T>
operator T () const {
return static_cast<T>(lhs.value) / static_cast<T>(rhs.value);
}
private:
const MyClass& lhs;
const MyClass& rhs;
};
那么您的代码将如下所示:
constexpr DivideMyClass operator/(const my_class& a, const my_class& b)
{
return DivideMyClass{a, b};
}
double d = MyClass{21} / MyClass{5}; // will be equal to 4.2
为什么这个解决方案不好
该语言未重载按返回类型进行的除法运算。你的代码会让其他人觉得有bug。如果您广泛使用此方法,您将得到一个最不可读的代码
另一件事,转换是隐式完成的,没有任何说明是否真的在呼叫站点的操作员中进行了转换
您将阻止AAA idom(几乎总是使用自动)<代码>自动可能会破坏您的代码,这是一件坏事
像这样的技术应该用于模板表达式之类的东西。使用它进行简单的除法会混淆其他除法。您可以使用一些模板魔术和转换运算符。您可以首先为表达式定义一个简单的包装器:
struct DivideMyClass {
DivideMyClass(const MyClass& lhs_, const MyClass& rhs_) : lhs{lhs_}, rhs_{rhs} {}
template<typename T>
operator T () const {
return static_cast<T>(lhs.value) / static_cast<T>(rhs.value);
}
private:
const MyClass& lhs;
const MyClass& rhs;
};
那么您的代码将如下所示:
constexpr DivideMyClass operator/(const my_class& a, const my_class& b)
{
return DivideMyClass{a, b};
}
double d = MyClass{21} / MyClass{5}; // will be equal to 4.2
为什么这个解决方案不好
该语言未重载按返回类型进行的除法运算。你的代码会让其他人觉得有bug。如果您广泛使用此方法,您将得到一个最不可读的代码
另一件事,转换是隐式完成的,没有任何说明是否真的在呼叫站点的操作员中进行了转换
您将阻止AAA idom(几乎总是使用自动)<代码>自动可能会破坏您的代码,这是一件坏事
像这样的技术应该用于模板表达式之类的东西。用它进行简单的除法会使其他人感到困惑
我可以根据接受结果的变量类型进行选择吗?即int
result=a/b返回int,但double result=a/b返回double
如果你下定决心要做这件事,你可以,但这很复杂,我不推荐。您必须仔细权衡优势与引入的复杂性。您可以通过惰性评估来实现这一点:
struct X {
int value;
};
struct X_op_proxy {
const X& lhs;
const X& rhs;
template <class T>
operator T() const { return static_cast<T>(lhs.value) / static_cast<T>(rhs.value); }
};
auto operator/(const X& lhs, const X& rhs) -> X_op_proxy
{
return {lhs, rhs};
}
int main()
{
X x1{11}, x2{2};
int i = x1 / x2;
cout << i << endl;
float f = x1 / x2;
cout << f << endl;
}
struct X{
int值;
};
结构X_op_代理{
常数X&lhs;
const X&rhs;
模板
运算符T()常量{return static_cast(lhs.value)/static_cast(rhs.value);}
};
自动运算符/(常数X和lhs,常数X和rhs)->X_操作_代理
{
返回{lhs,rhs};
}
int main()
{
xx1{11},x2{2};
int i=x1/x2;
库特
我可以根据接受结果的变量类型进行选择吗?即int
result=a/b返回int,但double result=a/b返回double
如果你下定决心要这么做,你可以这么做,但这很复杂,我不建议你这么做。你必须仔细权衡好处与引入的复杂性。你可以通过惰性评估来做到这一点:
struct X {
int value;
};
struct X_op_proxy {
const X& lhs;
const X& rhs;
template <class T>
operator T() const { return static_cast<T>(lhs.value) / static_cast<T>(rhs.value); }
};
auto operator/(const X& lhs, const X& rhs) -> X_op_proxy
{
return {lhs, rhs};
}
int main()
{
X x1{11}, x2{2};
int i = x1 / x2;
cout << i << endl;
float f = x1 / x2;
cout << f << endl;
}
struct X{
int值;
};
结构X_op_代理{
常数X&lhs;
const X&rhs;
模板
运算符T()常量{return static_cast(lhs.value)/static_cast(rhs.value);}
};
自动运算符/(常数X和lhs,常数X和rhs)->X_操作_代理
{
返回{lhs,rhs};
}
int main()
{
xx1{11},x2{2};
int i=x1/x2;
无法根据什么进行选择?将constexpr T操作符/
更改为constexpr int操作符/
?@appleapple我想要的有时候是double
,有时候是int
@VioletGiraffe这确实是个问题:)std::enable_if
和操作符/
的多个定义/重载,我认为。选择基于什么?将constexpr T操作符/
更改为constexpr int操作符/
?@appleapple我想有时候我想得到double
,有时候得到int
@VioletGiraffe,这确实是个问题:)std::enable_if
和操作符/
的多个定义/重载,我认为。是的,但这很糟糕。我可以根据接受结果的变量类型进行选择吗?即int result=a/b
返回int
,但double result=a/b
返回double?@vladon否,您不能t@vladon你可以做的是用代理类进行延迟计算。但这太麻烦了。是的,但这很糟糕。我可以根据变量accepti的类型进行选择吗ng结果?即int result=a/b
返回int
,但double result=a/b
返回double?@vladon否,您不能t@vladon你能做的就是用代理类进行懒惰的评估。但是这太麻烦了哇!太棒了!我认为这是不可能的:-)这就是为什么我问得这么愚蠢(第一次看)这里的问题:-)谢谢!为什么不简单地X\u op\u代理运算符/(const X&lhs,const X&rhs)
?@W.F.只是一种替代语法,没关系。bolov,对于auto i=x1/x2
是否可以这样做以返回double
(例如)默认情况下?@vladon但我相信默认模板或重载强制转换操作符都不会以期望的行为结束哇!太好了!我认为这是不可能的:-)这就是为什么我在这里问这么愚蠢的问题:-)谢谢!为什么不干脆X_op_代理操作符/(const X&lhs,const X&rhs)
?@W.F.只是一种替代语法,不要紧。bolov,对于默认情况下返回double
(例如)的auto i=x1/x2
,是否可以这样做?@vladon但我相信默认模板或重载cast操作符不会在所需的beh中结束