C++ 有没有办法定义一个;“加倍”;操作人员

C++ 有没有办法定义一个;“加倍”;操作人员,c++,c++11,operator-overloading,template-argument-deduction,C++,C++11,Operator Overloading,Template Argument Deduction,我有一个类,它表示一个只能接受整数值或半整数值的量,因此在内部将其值存储为一个两倍于该值的整数。也就是说:0.5的值存储为1,1存储为2,1.5存储为3,等等。我们用存储值int TwoA将其称为class a 这将强制A值正确地为整数或半整数。因为我经常需要使用它们作为它们的真实值,所以我自然地对double操作符进行了转换,该操作符只返回0.5*TwoA 但是,我经常需要使用两倍的值。我认为编写2*a(a是a类型的对象)直接返回a中存储的TwoA值会很好 理想情况下,我想做一个操作符,只在左

我有一个类,它表示一个只能接受整数值或半整数值的量,因此在内部将其值存储为一个两倍于该值的整数。也就是说:0.5的值存储为1,1存储为2,1.5存储为3,等等。我们用存储值
int TwoA
将其称为
class a

这将强制
A
值正确地为整数或半整数。因为我经常需要使用它们作为它们的真实值,所以我自然地对
double
操作符进行了转换,该操作符只返回
0.5*TwoA

但是,我经常需要使用两倍的值。我认为编写
2*a
a
a
类型的对象)直接返回
a
中存储的
TwoA
值会很好

理想情况下,我想做一个操作符,只在左侧乘以
2
时才这样做。隐式演员阵容将涵盖所有其他情况

在C++中有什么办法可以做到这一点吗?我想到了某种模板乘法运算符

只需定义

friend double operator*(int lhs, const A& rhs)
{ return (lhs == 2) ? rhs.TwoA_ : lhs * static_cast<double>(rhs); }
friend双运算符*(int-lhs、const-A和rhs)
{return(lhs==2)?rhs.TwoA_u2;:lhs*static_cast(rhs);}
这不是我要找的
2*a
保证是
int
(但通常
an_int*a
不是),我想返回一个int

这是一个好奇的问题;如果你只想评论“你为什么要这么做?”(或其变体),请保持沉默


编辑:我的意思是在左边乘以整数文本
2
(不是一个整数变量,测试它是否有值2)

理解您的问题是,是否可以重载
*
运算符,使其根据其中一个参数的值返回不同的数据类型,简单的回答是:不

答案很长:不,但可能是的

double operator*(const int lhs, const A& rhs);
该操作符必须在编译时知道
lhs
是否为
2
,这是无法保证的。这意味着必须在运行时决定如何处理
lhs
2
的情况。但运算符返回的数据类型必须在编译时已知

double operator*(const some_type_1& lhs, const A& rhs);
int operator*(const some_type_2& lhs, const A& rhs);
这将得到两种不同的返回类型,但只有在编译时知道这些参数类型是什么

template<int T>
struct special_number{};
//...
template<>
int operator*(const special_number<2>&, const A& rhs){
  return rhs.TwoA_;
}

template<int T>
double operator*(const special_number<T>&, const A& rhs){
  return (static_cast<double>(rhs) / 2.0) * T;
}

//usage
int answer1 = special_number<2> * my_a_object;
double answer2 = special_number<3> * my_a_object;
模板
结构特殊_数{};
//...
模板
整型运算符*(常数特殊数和常数A和rhs){
返回rhs.TwoA_u2;;
}
模板
双运算符*(常数特殊编号和常数A和rhs){
返回(静态_铸造(rhs)/2.0)*T;
}
//用法
int answer1=特殊编号*我的对象;
双重应答2=特殊号码*我的对象;
这样就可以了

struct two_t {
  constexpr two_t() {};
  template<class T>
  constexpr operator T()const{return 2;}
};
constexpr two_t two;
是你能做的最好的了

表达式的类型不依赖于值,除非在特殊情况下,常数
0
可以转换为指针,并可能导致不同的重载分辨率

当作为参数传递到
*
时,不能利用该特殊情况使
2变得特殊

现在

constepr std::ptrdiff\t from\u位(std::integer\u序列){
返回0;
}
constexpr std::ptrdiff t compile\u time\u pow(std::ptrdiff t base,std::size\u t exp){
返回exp?base*compile_time_pow(base,exp-1):std::ptrdiff_t(1);
}
模板
constexpr std::ptrdiff_t from_位(std::integer_序列){
返回
编译时间(10,sizeof…(cs))*(c0-'0')
+从_位(std::integer_序列{});
}
模板
constexpr自动运算符“”\u integer(){
返回std::积分_常量{};
}
现在
2\u integer
是一个编译时
std::ptrdiff\u t
的值
2
,其值以其类型编码


因此,可以重写
2*a
以返回与
3*a
2*a

不同的网络类型。对不起,
2*a
3*a
不能有不同的类型。@aschepper:是的,只有模板参数才能有不同的类型,例如
a.scaleby()
可以有与
a.scaleby()不同的类型。
@aschepler,除非您提供原因,否则您的答案完全没有帮助。@DanielGr:这是您希望引用标准的语言律师原因吗?或者知道重载解析只使用参数类型而不使用参数值就足够了吗?请注意,这是在浪费时间--double可以精确地存储半整数,而不会出现表示错误(除非您远远超过
INT\u MAX
),并且如果编译器可以看到您的转换,它将内联它,并删除多余的乘法。我是否会错误地建议在这里使用std::integral_常量而不是特殊的_数?我想我应该在我最初的问题中更清楚一点。我不想讨论
x*a
的情况,其中
x
正好有值2。我的意思是在左边乘以2。我想可能会使用类似于
模板自动操作符*(int N,A)->typename std::enable_if::type
——我理解这缺少了一些东西,但我认为它可能会以某种方式进行。不,您的
N
必须在编译时已知,并且必须保证在编译时已知才能工作。传递给函数的参数在编译时是已知的,但在运行时也是动态的。使用类似于exposed(或std::integral_constant,如John P所述)的方法可以让您在编译时了解要使用哪个重载函数,但在我看来,这在大多数情况下都是过分的。还要记住,编译器优化可能会完全减少原始post的运行时检查,因为它确实看到使用了常量
2
。我意识到这更像是一个概念问题
friend double operator*(two_t lhs, const A& rhs)
{ return rhs.TwoA_; }
friend double operator*(const A& lhs, two_t lhs)
{ return lhs.TwoA_; }
constexpr std::ptrdiff_t from_digits(std::integer_sequence<char>) {
  return 0;
}
constexpr std::ptrdiff_t compile_time_pow( std::ptrdiff_t base, std::size_t exp ) {
  return exp ? base * compile_time_pow( base, exp-1 ) : std::ptrdiff_t(1);
}
template<char c0, char...cs>
constexpr std::ptrdiff_t from_digits(std::integer_sequence<char, c0, cs...>) {
  return
    compile_time_pow(10, sizeof...(cs))*(c0-'0')
    + from_digits( std::integer_sequence<char, cs...>{} );
}
template<char...cs>
constexpr auto operator"" _integer() {
  return std::integral_constant<std::ptrdiff_t, from_digits( std::integer_sequence<char, cs...>{} )>{};
}