2017-05-19 3 views
0

私は何かが失敗するようにstatic_assertを使用しようとしています。特定のテンプレート関数を特定の方法でインスタンス化しようとすると、コンパイラエラーが生成されます。私はそれを働かせることができたが、それは本当に醜いだった。これを行う簡単な方法はありますか?static_assert(false)を呼び出す正しい方法は何ですか?

これが私の最初の試みでした。これはまったく機能しませんでした。誰もこの関数を使用しようとしても、常にエラーを生成します。

template< class T > 
void marshal(std::string name, T *value) 
{ 
    static_assert(false, "You cannot marshal a pointer."); 
} 

私の2番目の試みです。それは実際に動作します。これを呼び出さないとエラーは発生しません。これを呼び出すと、この行を指し、それをインスタンス化しようとしたコードを指す非常に読みやすいエラーメッセージが表示されます。

template< class T > 
void marshal(std::string name, T *value) 
{ 
    static_assert(std::is_pod<T>::value && !std::is_pod<T>::value, "You cannot marshal a pointer."); 
} 

問題は、このコードが最高で醜いということです。それはハックのように見えます。私は次回最適化レベルを変更したり、コンパイラを再コンパイルしたり、くしゃみをしたりするなど、コンパイラはこの2番目のケースが最初のものと同じであることを認識し、両方とも動作を停止することに気付きます。

私がやろうとしていることをするためのより良い方法はありますか?

ここにいくつかの文脈があります。 marshal()のいくつかの異なるバージョンを用意して、さまざまな入力タイプに対応したいと考えています。テンプレートをデフォルトのケースとして使用する1つのバージョンが必要です。 char *以外のポインタを特に許可しない別のものが必要です。

何をしようとする
void marshal(std::string name, std::string) 
{ 
    std::cout<<name<<" is a std::string type."<<std::endl; 
} 

void marshal(std::string name, char *string) 
{ 
    marshal(name, std::string(string)); 
} 

void marshal(std::string name, char const *string) 
{ 
    marshal(name, std::string(string)); 
} 

template< class T > 
void marshal(std::string name, T value) 
{ 
    typedef typename std::enable_if<std::is_pod<T>::value>::type OnlyAllowPOD; 
    std::cout<<name<<" is a POD type."<<std::endl; 
} 

template< class T > 
void marshal(std::string name, T *value) 
{ 
    static_assert(false, "You cannot marshal a pointer."); 
} 

int main (int argc, char **argv) 
{ 
    marshal(“should be pod”, argc); 
    marshal(“should fail to compile”, argv); 
    marshal(“should fail to compile”, &argc); 
    marshal(“should be std::string”, argv[0]); 
} 
+0

のために1次テンプレートの定義を変更する必要がありますか? – cpplearner

+0

@cpplearner一部の人は、オプションパラメータのenable_ifをテンプレートに隠しています。これは、発信者が誤ってその(偽の)パラメータを埋めることができないため、より良いようです。 –

答えて

4

これを行う方法はありません。あなたはあなたのコンパイラで動作させることができるかもしれませんが、結果として得られるプログラムは診断が必要ではありません。

=deleteを使用してください。

template< class T > 
void marshal(std::string name, T *value) = delete; 
+0

興味深い。私は、コピーコンストラクタのようなデフォルトのメソッドを削除するために使用されたdeleteを見ただけです。私はあなたがこれをすることができるのか分からなかった。私は試してみる必要があります。 –

2

[temp.res]/8に応じて(も、あなたの回避策が失敗する可能性が)病気に形成されたことを運命づけられている(強調鉱山):名前はタイプ名です

知るには、構文を使用できますすべてのテンプレート を確認してください。 プログラムは、必要な一切の診断を悪い形成されていない、場合:
- テンプレートと テンプレート内の文がインスタンス化されていない場合有効な分業がテンプレートやconstexprのサブステートメントのために生成することができ、または矛盾に頼って(...)

+0

私はこの10回の昨夜を読んでいます。そして今朝もまた。私はまだそれが何を言っているのか分からない。 : –

+1

残念なことに、標準は非常に正確ですが、時には理解が難しい言葉を使って書かれています...基本的には、インスタンス化できないテンプレートを作成することはできません(構造テンプレートや関数テンプレートの場合は問題ありません)言い換えれば、テンプレートをインスタンス化できる少なくとも1つのパラメータセットが存在する必要があります –

2

は確かに最高ではありませんが、簡単な方法があります:

template <class...> 
struct False : std::bool_constant<false> { }; 

template <class T> 
void bang() { 
    static_assert(False<T>{}, "bang!"); 
} 

は、なぜこれが下に落ちません「有効な専門化なし」の場合?
さて、あなたは実際に有効な特殊化を行うことができ、コードの後半でいるので:もちろん

template <> 
struct False<int> : std::bool_constant<true> { }; 

int main() { 
    bang<int>(); // No "bang"! 
} 

、誰が実際に実際のコードでは、あなたのアサーションを破るためにFalseを専門にするつもりはないが、それは可能です:)

+0

コンパイラが有効な特殊化がないことを知っている場合(つまり、Falseは特殊化されません。コード)は、あなたのプログラムが悪意のあるコードであることを証明しないでしょうか?つまり、これがルールを避けることは確かですか、それとも気づかないのですか? – Yakk

+0

@Yakkそれは伸びていると思います。現在のプログラムではないことは、その箇条書きAFAICTの範囲外です。 'False'を特化した別のバイナリを動的にロードすると、私のプログラムはうまく形成されましたか? – Quentin

+0

だから、あなたはよくわからないのですか?私は、静的に偽をアサートできるようにしたいという妥当性を得るが、標準は「いいえ」と書かれていた。あなたが端に近づくときには、標準の正確な言葉遣いがたくさんあります。それは、専門化をインスタンス化可能とする議論はないと述べている。 'False :std :: bool_constant {}'が実際にいくつかの '?'に存在するまで、それは特殊化をインスタンス化可能にする引数がないことは事実です。私は間違っているかもしれません。私はしばしばです。しかし、私は "病気の形成、診断不要"の周りの注意が豊富になるだろう – Yakk

1

あなたが最初の場所でtemplate< class T > void marshal(std::string name, T *value)を持っている理由私は理解していません。これは、プライマリテンプレートのstatic_assertでなければなりません。

ある

、あなたはなぜ `のtypedef typenameにはstd :: enable_if`

template< class T > 
void marshal(std::string name, T value) 
{ 
    static_assert(std::is_pod<T>::value); 
    static_assert(!std::is_pointer<T>::value); 
    std::cout<<name<<" is a POD type."<<std::endl; 
} 
+0

ありがとうございます。私は似たような解決策を探していただけです。非常に多くのオプションがあり、適切なものを選ぶのは難しいです。 –

+0

私は別の回答を選択しましたが、あなたの回答は近いです。 =削除オプションは、読者にはもう少し明らかでした。しかし、あなたの答えはもっと柔軟に思えるし、将来このトリックが必要になるかもしれない。ありがとうございました。 –

関連する問題