2017-01-28 29 views
4

私がしようとしているのは、この単純なテンプレートクランプ機能です。 実行時とコンパイル時にupper >= lowerを確実にしたいです。リファレンステンプレートの引数型のstatic_assert

template <typename T> 
T clamp(const T& lower, const T& upper, const T& n) 
{ 
    weak_assert(upper >= lower); 
    return std::max(lower, std::min(n, upper)); 
} 

書くために合理的なようだ:

static_assert(upper >= lower, "invalid bounds"); 

constexprの引数で呼び出されたときしかし、コンパイラは私にこれを与える:

Static_assert expression is not an integral constant expression 
In instantiation of function template specialization 'clamp<int>' requested here 

が適切にこれを達成するためにどのような方法があります? constexprで呼び出された場合(たとえば、clamp<int>(0, 10, myvar) static_assertがそうでなければ通常のダイナミックアサートを行います、解雇すべきですか?

+0

あなたは、静的な値のメンバーでヘルパー構造体を使って、constexprの評価を実施し、その中でstatic_assertを置くことができます。それはconstexprと非constexpr呼び出しの呼び出しシグネチャを変更します...私はオプションのstatic_assertを実行する方法は知られておらず、constexpr関数の評価がコンパイル時に実際に評価されるという事実はほとんど意味がありませんテンプレートパラメータを設定するために使用されない限り、指定されません。 – rubenvb

+1

C++ 14以降では、constexpr関数にassert()を追加できます。 – kamikaze

答えて

6

C++ 14 assert()以降では、constexprの関数で許可されているが、それでもC++ 11であなたはそれをだますことができますでoperator ,を使用して:Cであなたがconstexprの文脈における関数のパラメータを使用することはできません...しかし、多かれ少なかれ、あなたのパラメータを包むことができ、何をしたいですし++ので

#include <cassert> 

template <typename T> 
constexpr T clamp(const T& lower, const T& upper, const T& n) 
{ 
    return assert(upper >= lower), std::max(lower, std::min(n, upper)); 
} 
+0

それはいいトリックですが、私は 'assert'のカスタムラッパーを使っています。これは、ログに書き込むために必要で、Android上で実際の' assert'を呼び出さないからです。 – Hedin

+0

@Hedinその場合、 'static_assert()'で 'constexpr'と' weak_assert() 'でランタイム関数の2つの異なる関数を使用する必要があります。私。どちらが正しいかを決定するためには、関数のユーザーにそれを任せなければなりません。 – kamikaze

1

コンパイラがここstatic_assertを禁止する権利でありますstd::integral_constantに入れて、型を推測できるように値を推測します。例:

#include <algorithm> 
#include <type_traits> 

template <class T, T val> 
using ic = std::integral_constant<T, val>; 

template <typename T, T lower, T upper> 
T clamp(ic<T, lower>, ic<T, upper>, const T& n) 
{ 
    static_assert(upper >= lower, "invalid bounds"); 
    return std::max(lower, std::min(n, upper)); 
} 

int main() { 
    clamp(ic<std::size_t, 5>{}, ic<std::size_t, 10>{}, std::size_t{8}); 
    // clamp(ic<std::size_t, 10>{}, ic<std::size_t, 5>{}, std::size_t{8}); // static assertion failed: invalid bounds 
} 

[live demo]

+0

私はそれを完全に理解していませんが、それは涼しいです。 +1 – javaLover