Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 关于运算符+;模板类中的重载_C++_Templates_Operator Overloading - Fatal编程技术网

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中唯一一个在默认情况下仅对此发出警告的编译器,其他所有编译器在默认情况下都会给出一个错误)。实际上,您可以在函数中使用该事实。它比自定义特性更可靠。