2017-02-23 6 views
2

コンパイル時定数引数で呼び出された場合、引数の値が0ならばコンパイル時エラーが発生するような関数を記述しようとしています。 [static_assert]に一致しますが、実行時には計算された値で呼び出すことができます。ちょっとこのようなコンパイル時定数パラメータが間違っているとコンパイル時エラーが発生する

何か:

template<int N> void f(N){ 
    static_assert(N == 5, "N can only be 5."); 
    do_something_with(N); 
} 

void f(int N){ 
    if(N == 5){ 
    do_something_with(N); 
    } 
} 

volatile int five = 5; 
volatile int six = 6; 

int main() { 
    f(5); //ok 
    f(6); //compile-time error 
    f(five); //ok 
    f(six); //run-time abort 

    return 0; 
} 

私はこれをどのように行うことができますか?

また、可能であれば、単純なf(something)の構文を保持したいと考えています。このコードは、テンプレート構文に精通していない初心者プログラマが使用できるライブラリを対象としているためです。

+2

値は、{行 'テンプレートボイドF(N)ので、推測することはできません'正しいことはできません –

+1

コンパイル時間または実行時。あなたは選択する(または2つの機能を作る)必要があります。 – xinaiz

+0

テンプレートのものではなく 'constexpr'でそれを行う方法はありますか? – AJMansfield

答えて

5

私が想像できる最高のものは、例外をスローするconstexpr関数です。

コンパイル時に実行すると、throwはコンパイルエラーを引き起こします。 EDIT - - 実行時に実行された場合、

#include <stdexcept> 

constexpr int checkGreaterThanZero (int val) 
{ return val > 0 ? val : throw std::domain_error("!"); } 

int main() 
{ 
    // constexpr int ic { checkGreaterThanZero(-1) }; // compile error 

    int ir { checkGreaterThanZero(-1) }; // runtime error 
} 

ような例外

いろいろ書い投げる

ユーリkilocheckで指摘したように、代わりに例外をスローするの、あなたがstd::abort()を呼び出すことができますが、異なる構文で

constexpr int checkGreaterThanZero (int val) 
{ return val > 0 ? val : (std::abort(), 0); } 
+1

'std :: abort'も大丈夫です。しかし、このような関数はコンパイル時に評価されるためにはconstexprコンテキストで呼び出される必要があります。 –

+0

@yurikilochek - 私はこの種の問題を解決するために 'スロー 'を使用していましたが、私はそれについて考えませんでした。あなたが正しい;ありがとう。私の答えをそれに従って修正した – max66

2

例によって、あなたが行うことがあります。パラメータとして機能するように渡さ

template <int N> 
using int_c = std::integral_constant<int, N>; 

namespace detail { 
    template <std::size_t N> 
    constexpr int to_number(const int (&a)[N]) 
    { 
     int res = 0; 
     for (auto e : a) { 
      res *= 10; 
      res += e; 
     } 
     return res; 
    } 
} 

template <char ... Ns> 
constexpr int_c<detail::to_number({(Ns - '0')...})> operator ""_c() 
{ 
    return {}; 
} 

#if 1 // Write this way 
// Compile time 
template <int N> void f(int_c<N>) = delete; 
void f(int_c<5>) { do_something_with(5); } 

#else // Or like this 
// Compile time 
template <int N> 
void f(int_c<N>) 
{ 
    static_assert(N == 5, "!"); 
    do_something_with(N); 
} 

#endif 

// Runtime 
void f(int N){ 
    if (N == 5) { 
     std::abort(); // Or any other error handling 
    } 
    f(5_c); 
} 

int main(){ 
    f(5_c); // ok 
    // f(6_c); // Won't compile 
    f(5); // ok 
    f(6); // abort at runtime 
} 

Demo

関連する問題