66

私は役立つエラーやメッセージを提供するのが好きで、自分のためにもそうしたいと思っていますstatic_assert。問題は、それらがテンプレート パラメーターに依存していることです。通常、これらのパラメーターはエラーが発生したために途中で表示されますが、それらはあいまいであるかグループ化されていないため、意味があります。例:

template<class T>
struct fake_dependency{
  static bool const value = false;
};

template<class T, class Tag>
struct Foo{
  Foo(){}

  template<class OtherTag>
  Foo(Foo<T, OtherTag> const&){
    static_assert(fake_dependency<T>::value, "Cannot create Foo<T,Tag> from Foo<T,OtherTag>.");
  }
};

int main(){
    Foo<int, struct TagA> fA;
    Foo<int, struct TagB> fB(fA);
}

MSVC での出力:

src\main.cpp(74): error C2338: Cannot create Foo<T,Tag> from Foo<T,OtherTag>.
          src\main.cpp(84) : see reference to function template instantiation 'Foo<T,Tag>::Foo<main::TagA>(const Foo<T,main::TagA> &)' being compiled
          with
          [
              T=int,
              Tag=main::TagB
          ]

1 つのタグは関数テンプレート自体に記載されており、もう 1 つのタグはクラス テンプレートの下に記載されています。あまり良くない。GCCが出力するものを見てみましょう:

prog.cpp: In constructor 'Foo<T, Tag>::Foo(const Foo<T, OtherTag>&) [with OtherTag = main()::TagA, T = int, Tag = main()::TagB]':
prog.cpp:18:32:   instantiated from here
prog.cpp:12:5: error: static assertion failed: "Cannot create Foo<T,Tag> from Foo<T,OtherTag>."

はるかに優れていますが、まだ実際にはどこにあるかはわかりませんstatic_assert。そして、いくつかのパラメータ、テンプレート、またはその両方を想像してみてください。震える

これを回避する 1 つの方法は、両方のタグをテンプレート パラメーターとして受け取る中間構造体を使用することです。

template<class Tag, class OtherTag>
struct static_Foo_assert{
    static_assert(fake_dependency<Tag>::value, "Cannot create Foo<T,Tag> from Foo<T,OtherTag>.");
};

template<class T, class Tag>
struct Foo{
  Foo(){}

  template<class OtherTag>
  Foo(Foo<T, OtherTag> const&){
      static_Foo_assert<Tag, OtherTag> x;
  }
};

出力をもう一度見てみましょう。

src\main.cpp(70): error C2338: Cannot create Foo<T,Tag> from Foo<T,OtherTag>.
          src\main.cpp(79) : see reference to class template instantiation 'static_Foo_assert<Tag,OtherTag>' being compiled
          with
          [
              Tag=main::TagB,
              OtherTag=main::TagA
          ]

ずっといい!GCCが言うことは次のとおりです。

prog.cpp: In instantiation of 'static_Foo_assert<main()::TagB, main()::TagA>':
prog.cpp:17:40:   instantiated from 'Foo<T, Tag>::Foo(const Foo<T, OtherTag>&) [with OtherTag = main()::TagA, T = int, Tag = main()::TagB]'
prog.cpp:23:32:   instantiated from here
prog.cpp:8:5: error: static assertion failed: "Cannot create Foo<T,Tag> from Foo<T,OtherTag>."

見た目は悪くない。問題:エラーメッセージはstatic_assert文字列リテラルである必要があるため、すべてのテンプレートに対してそのような構造体を作成する必要があります...

さて、私の質問ですが、どうにかして型名を に直接含めることはできますstatic_assertか? お気に入り

static_assert(..., "Cannot create Foo<" T "," Tag "> from Foo<" T "," OtherTag ">.");

出力例:

Foo<int,main::TagA>から作成できませんFoo<int,main::TagB>

または、それが達成できない場合は、何とかしてエラー メッセージを追加のテンプレート パラメーターにして、問題ないようにすることはできますか?

4

5 に答える 5

15

私のハック

コード:

template <typename Assertion>
struct AssertValue : AssertionChecker<Assertion::value, Assertion>
{
    static_assert(AssertionValue, "Assertion failed <see below for more information>");
    static bool const value = Assertion::value;
};

アサーションをチェックし、::value失敗した場合はタイプをダンプできます。

使用法:

// Bad indentation used to show parts
static_assert(
    AssertValue<
        std::my_check<
            T0, decltype(*somethingComplicated), T7::value_type
        >
    >, 
    "something horrible happened"
);

std::my_check<...>::valueチェックのブール結果はどこにありますか

完全なSSCCEの例については、 IDEOneの例を参照してください。

例のエラー メッセージ:

prog.cpp: In instantiation of 'AssertValue<std::is_base_of<IMyInterface, MyBadType> >':
prog.cpp:37:69:   instantiated from 'void MyFunction(IteratorType, IteratorType) [with IteratorType = __gnu_cxx::__normal_iterator<MyBadType*, std::vector<MyBadType> >]'
prog.cpp:60:38:   instantiated from here
prog.cpp:9:5: error: static assertion failed: "Assertion failed <see below for more information>"
prog.cpp: In function 'void MyFunction(IteratorType, IteratorType) [with IteratorType = __gnu_cxx::__normal_iterator<MyBadType*, std::vector<MyBadType> >]':
prog.cpp:60:38:   instantiated from here
prog.cpp:39:5: error: static assertion failed: "iterator passed does not reference IMyInterface items"

説明

アサーションが失敗すると、AssertValue のテンプレート引数が出力されるため、チェックの完全なテンプレート展開が出力されます。たとえば、 をチェックしていた場合std::is_base_of、チェックの完全なタイプが出力されますstd::is_base_of<IMyInterface, MyBadType>。これで、失敗したアサーションで使用された型が正確にわかります。

唯一の問題は、これが結果を に入れるテンプレートでのみ機能することです::value。ただしtype_traits、主にこれを使用し、後藤標準です。

于 2012-11-13T18:05:02.977 に答える
3

少しフープジャンプすることで、文字列リテラルをテンプレートの非型パラメータとして渡すことができます。ただし、の2番目の引数static_assertは、たとえばアドレス定数式ではなく文字列リテラルに制限されているため、残念ながらこれはあまり使用されません。

残念ながら、あなたの最善の策は、委員会またはコンパイラの作成者に施設を拡張するよう働きかけることだと思います。

于 2011-10-02T18:21:04.843 に答える
-4

std::type_infoメンバーを持っていますconst char* name():

#include <typeinfo>
using namespace std;

//...

const char* name = type_info(T).name();
于 2011-08-18T12:49:54.553 に答える