C++ 关于运算符+;模板类中的重载
我正在做一些模板的练习,我被这个问题困住了。我有一个类,它用编译时指定的底层类型和起始值表示计数器。我想在计数器类型和具有适当类型的整数类型之间支持算术运算符。例如,我想在编译时拒绝将带有C++ 关于运算符+;模板类中的重载,c++,templates,operator-overloading,C++,Templates,Operator Overloading,我正在做一些模板的练习,我被这个问题困住了。我有一个类,它用编译时指定的底层类型和起始值表示计数器。我想在计数器类型和具有适当类型的整数类型之间支持算术运算符。例如,我想在编译时拒绝将带有uint8\t的计数器的和作为带有int类型变量的底层类型。到目前为止还不错 我得到的是,即使是应该正确的操作也不会编译。这里主要部分来说明问题 #include <iostream> #include <type_traits> #include <limits> te
uint8\t
的计数器的和作为带有int
类型变量的底层类型。到目前为止还不错
我得到的是,即使是应该正确的操作也不会编译。这里主要部分来说明问题
#include <iostream>
#include <type_traits>
#include <limits>
template <typename Source, typename Dest, std::enable_if_t<std::is_integral<Source>::value && std::is_integral<Dest>::value, int> =0>
struct type_not_narrow{
static constexpr bool value= std::numeric_limits<Source>::max() <= std::numeric_limits<Dest>::max();
};
template<typename T, T N, std::enable_if_t<std::is_integral<T>::value, int> =0>
class basic_counter{
T cnt;
basic_counter(T initializer): cnt(initializer){}
public:
basic_counter(): cnt(N){};
template <typename T1, T1 N1, typename T2, T2 N2>
friend basic_counter<typename std::common_type<T1,T2>::type, N1+N2> operator+(const basic_counter<T1, N1>& lhs,
const basic_counter<T2, N2>& rhs);
template <typename X, typename U, U M, std::enable_if_t<type_not_narrow<X, U>::value, int>>
friend basic_counter<U,M> operator+(const basic_counter<U, M> lhs, const X step);
operator T() const{
return cnt;
}
};
template <typename T1, T1 N1, typename T2, T2 N2>
basic_counter<typename std::common_type<T1,T2>::type, N1+N2> operator+(const basic_counter<T1, N1>& lhs,
const basic_counter<T2, N2>& rhs){
return {lhs.cnt+rhs.cnt};
}
template<typename X, typename T, T N, std::enable_if_t<type_not_narrow<X, T>::value, int> =0>
basic_counter<T,N> operator+(const basic_counter<T, N> lhs, const X step){
basic_counter<T,N> c=lhs;
c.cnt+=step;
return c;
}
int main() {
basic_counter<unsigned long int, 1> c1;
basic_counter<unsigned long int, 2> c2;
basic_counter<unsigned long int, 3> c3=c2+c1;
unsigned long int ul=5;
int i=5;
char ch=5;
basic_counter<unsigned long int, 2> c4=c2+5;
basic_counter<unsigned long int, 2> c5=c2+i;
basic_counter<unsigned long int, 2> c5bis=c2+ch;
basic_counter<unsigned long int, 2> c6=c2+ul;
//should not compile due to narrowing (and it's correct)
//basic_counter<unsigned long int, 2> c7=c2+5.2;
//basic_counter<uint8_t,0> c8;
//c8=c8+i;
basic_counter<uint8_t,0> c9;
//this should compile
c9=c9+1;
//this should not
c9=c9+2000;
return 0;
}
#包括
#包括
#包括
模板
结构类型不窄{
static constexpr bool value=std::numeric_limits::max()如果更正注释中提到的未定义行为,则此表达式:
c9=c9+1;
编译失败,因为1是int
文本。编译器为此抛出一些奇怪的错误,因为它试图通过调用隐式cast运算符将c9
转换为整数,并调用私有值构造函数,使整个过程正常工作
因此,这条线将起作用:
基本计数器c10=c9+uint8(1);
这是一个很难的妥协,因为它仍然不可能使用函数参数的值来代替模板参数和静态断言(除非采用了)。
你瞄准哪种C++标准?如果你有严肃的代码> CONTXPRPR <代码>支持(C++ 14和以上),那么最后一个是不可能的。你有一个简单的错误:好的,谢谢@walmut的更正。关于你在那几行中关于UB的话,你是对的,我在写这个问题时很快改变了代码,以减少空间,而没有对我正在做的事情给予应有的注意。我会再次打断你的定义和作业。@DanielJour你能更好地解释一下什么是什么吗你指的是“严重的constexpr
support”?标记为//的行应该可以编译,但在gcc 7.4中它不能为我编译。
是否通过对@walnut的评论进行编辑来修复?我认为这里重要的一点是,每个整数文本,无论多么小,都至少具有int
的整数秩。您不能编写一个较低ra的整数文本nk(例如,uint8\t
)没有强制转换。您可能可以定义一个数值文本运算符模板,该模板返回具有用户定义文本的低秩整数类型。好的,我知道“问题”是什么了@parktomi I首先避免了以建议的形式进行显式强制转换的想法,主要是因为它没有正确地解决文本值的转换问题。这将取决于用户是否编写`(uint8\t)2000;`。我查找了数值文字运算符模板@walnut:这有点奇怪,但似乎是唯一的解决方案。链接的建议非常有趣,但我看到这是最近的,所以我想我们将等待在标准中看到它。@Zack用户不应该使用(uint8_t)2000
或uint8_t(2000)
首先。如果用户总是选择使用大括号构造临时变量,即uint8\u t{2000}
,那么当转换变窄时,他们保证得到诊断。这总是正确的,不仅仅是对于文本:使用大括号初始化不允许变窄参数(GCC是GCC/Clang/MSVC中唯一一个在默认情况下仅对此发出警告的编译器,其他所有编译器在默认情况下都会给出一个错误)。实际上,您可以在函数中使用该事实。它比自定义特性更可靠。