2017-03-22 14 views
2

私はC++で次のコードを書いています。私は言語にかなり新しいですが、私は:)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<Measure<10,Unit::cm>, Measure<10,Unit::cm>>::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特性を正しく返すのかどうかは不明です。 ご迷惑をおかけして申し訳ありません。

+0

この値は型の一部です。したがって、 'M1'と' M2'を追加する場合、結果の型は 'M1'にはなりません。 –

+0

@BoPersson、ご返信ありがとうございます。それは理にかなっていますが、戻り値の型はMeasureではありません。これはクラスではないからです。右? – user1390504

+0

ここに問題がありますが、完全な解決策はありません。有理数計算のためにいくらか類似した[''ヘッダー](http://en.cppreference.com/w/cpp/header/ratio)を見ると、追加のための関数がないことがわかりますが、代わりに結合された値を含む新しいタイプを生成します。おそらくあなたはその行に沿って何かをすることができます。 –

答えて

1

慎重にエラーメッセージを見てみましょう。

/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>();

問題は、以下の行で発生します(と同様の)

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

両方値と単位はあなたのケースでテンプレートの種類です。 M1::valueM2::valueを追加すると、が0でなければ、テンプレートパラメータを変更していて、タイプがM1と異なる場合があります。

+0

ご返信ありがとうございます。それは多くの意味があります。しかし、それはクラスではないので、 "Measure"型を作成することはできませんし、実際の戻り値の前に値や単位を知ることもできません。 – user1390504

+0

@ user1390504どのバージョンのC++を使用していますか? C++をお持ちの場合は、戻り値の型として 'auto'を使用してください。 C++ 11を使用している場合は、[trailing return type]を使用できます(http://stackoverflow.com/questions/12224325/what-is-the-meaning-of-auto-when-using-c-tr​​ailing-return -タイプ) – NathanOliver

関連する問題