【问题标题】:C++ value is not usable in a constant expressionC++ 值在常量表达式中不可用
【发布时间】:2017-03-22 10:50:44
【问题描述】:

我用 C++ 编写了以下代码。我必须承认我对这门语言还很陌生,但我正在努力学习:)

#include <iostream>
#include <cassert>

enum class Unit { km, m, cm };

template<int v, Unit u>
struct Measure {
    static const int value = v;
    static const Unit unit = u;
};


template<typename M1, typename M2>
struct Measures_same {
    static const bool value() {
        return M1::unit == M2::unit;
    }
};

template<typename M1, typename M2>
struct SmallestUnit {
    static const Unit value() {
        switch(M1::unit) {
            case Unit::km:
                return M2::unit;
            case Unit::m:
                switch (M2::unit) {
                    case Unit::km:
                        return M1::unit;
                    case Unit::m:
                        return M2::unit;
                    case Unit::cm:
                        return M2::unit;
                }
            case Unit::cm:
                return M1::unit;
        }
    };
};


template<typename M1, typename M2>
struct Measure_difference {
    static const int value(){
        if(Measures_same<M1,M2>::value()){
            return 0;
        }
        Unit smallestValue = SmallestUnit<M1, M2>::value();
        Unit largestValue;
        if(M1::unit == smallestValue){
            largestValue = M2::unit;
        }
        else{
            largestValue = M1::unit;
        }

        switch(smallestValue) {
            case Unit::m:
                switch (largestValue) {
                    case Unit::km:
                        return 1000;
                }
            case Unit::cm:
                switch (largestValue) {
                    case Unit::km:
                        return 1000 * 1000;
                    case Unit::m:
                        return 1000;
                }
        }
    }
};

template<typename M1, typename M2>
struct Measure_add {
    static const M1 value(){
        if(Measures_same<M1,M2>::value()){
            return Measure<(M1::value + M2::value), M1::unit>();
        }
        Unit smallestValue = SmallestUnit<decltype(M1::unit), decltype(M2::unit)>::value();

        int const difference = Measure_difference<M1,M2>::value();
        if(M1::unit == smallestValue){
            return Measure<(M1::value + (M2::value * difference)), M1::unit>();
        }
        else{
            return Measure<(M2::value + (M1::value * difference)), M2::unit>();
        }
    }
};

void testMeasuresSame(){
    assert((Measures_same<Measure<10,Unit::km>, Measure<10,Unit::km>>::value()) == true);
    assert((Measures_same<Measure<10,Unit::km>, Measure<10,Unit::m>>::value()) == false);
    assert((Measures_same<Measure<10,Unit::cm>, Measure<10,Unit::m>>::value()) == false);
}

void testSmallestUnit(){
    assert((SmallestUnit<Measure<1, Unit::km>, Measure<2, Unit::km>>::value()) == Unit::km);
    assert((SmallestUnit<Measure<10,Unit::km>, Measure<10,Unit::m>>::value()) == Unit::m);
    assert((SmallestUnit<Measure<10,Unit::cm>, Measure<10,Unit::m>>::value()) == Unit::cm);
}

void testMeasureDifference(){
    assert((Measure_difference<Measure<1, Unit::km>, Measure<2, Unit::km>>::value()) == 0);
    assert((Measure_difference<Measure<10,Unit::km>, Measure<10,Unit::m>>::value()) == 1000);
    assert((Measure_difference<Measure<10,Unit::cm>, Measure<10,Unit::m>>::value()) == 1000);
    assert((Measure_difference<Measure<10,Unit::cm>, Measure<10,Unit::km>>::value()) == 1000 * 1000);
}

void testMeasureAdd(){
    Measure_add<Measure<10,Unit::cm>, Measure<10,Unit::cm>>::value();
}

int main() {
    testMeasuresSame();
    testSmallestUnit();
    testMeasureDifference();
    testMeasureAdd();
    return 0;
}

现在在运行Measure_add&lt;Measure&lt;10,Unit::cm&gt;, Measure&lt;10,Unit::cm&gt;&gt;::value(); 行时,出现以下错误:

Scanning dependencies of target unitconverter
[ 95%] Building CXX object H08-unit-converter/CMakeFiles/unitconverter.dir/src/unitconverter.cxx.o
/unitconverter.cxx: In instantiation of ‘static const M1 Measure_add<M1, M2>::value() [with M1 = Measure<10, (Unit)2>; M2 = Measure<10, (Unit)2>]’:
/unitconverter.cxx:112:62:   required from here
/unitconverter.cxx:78:63: error: could not convert ‘Measure<20, (Unit)2>()’ from ‘Measure<20, (Unit)2>’ to ‘const Measure<10, (Unit)2>’
             return Measure<(M1::value + M2::value), M1::unit>();
                                                               ^
/unitconverter.cxx:84:78: error: the value of ‘difference’ is not usable in a constant expression
             return Measure<(M1::value + (M2::value * difference)), M1::unit>();
                                                                              ^
/unitconverter.cxx:82:19: note: ‘difference’ was not initialized with a constant expression
         int const difference = Measure_difference<M1,M2>::value();
                   ^
/unitconverter.cxx:84:78: note: in template argument for type ‘int’ 
             return Measure<(M1::value + (M2::value * difference)), M1::unit>();
                                                                              ^
/unitconverter.cxx:87:78: error: the value of ‘difference’ is not usable in a constant expression
             return Measure<(M2::value + (M1::value * difference)), M2::unit>();
                                                                              ^
/unitconverter.cxx:82:19: note: ‘difference’ was not initialized with a constant expression
         int const difference = Measure_difference<M1,M2>::value();
                   ^
/unitconverter.cxx:87:78: note: in template argument for type ‘int’ 
             return Measure<(M2::value + (M1::value * difference)), M2::unit>();
                                                                              ^

我想从 Measure_add 特征返回一个带有结果的 Measure。我真的不明白为什么我不能像这样使用差异。此外,我不确定我是否正确地返回了这样的 Measure 特征。 非常感谢任何帮助!

【问题讨论】:

  • 值是类型的一部分,所以M1M2相加时,结果类型不能是M1
  • @BoPersson,感谢您的快速回复。这是有道理的,但返回类型也不能是 Measure,因为它不是一个类;对吗?
  • 我在这里看到了一个问题,但我没有完整的解决方案。如果您查看与有理算术有些相似的&lt;ratio&gt; header,您会发现它没有加法函数,而是生成一个包含组合值的新类型。也许你可以沿着这条线做点什么。

标签: c++ unit-testing initialization expression constants


【解决方案1】:

仔细查看错误信息:

/unitconverter.cxx:78:63: 错误:无法将‘Measure<20, (Unit)2>()’‘Measure&lt;20, (Unit)2&gt;’转换为‘const Measure<10, (Unit)2>'
return Measure&lt;(M1::value + M2::value), M1::unit&gt;();

问题出现在下面一行(和类似的)

static const M1 value(){
    if(Measures_same<M1,M2>::value()){
        return Measure<(M1::value + M2::value), M1::unit>();
    }
    ...

在您的情况下,值和单位都是模板类型。当您添加M1::valueM2::value 时,您正在更改(其中之一)模板参数和类型可能与M1 不同,除非M2::value0

【讨论】:

  • 感谢您的快速回复。这很有意义。但是,我不能将类型设置为“Measure”,因为它不是一个类,我也不知道实际返回之前的值或单位,对吧?
  • @user1390504 您使用的是什么版本的 C++?如果你有 C++14,只需使用 auto 作为返回类型。如果你有 C++11,你可以使用 trailing return type
猜你喜欢
  • 1970-01-01
  • 2018-04-09
  • 1970-01-01
  • 2019-07-13
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
  • 1970-01-01
相关资源
最近更新 更多