在static_assert输出中集成类型名称? [英] Integrate type name in static_assert output?

查看:165
本文介绍了在static_assert输出中集成类型名称?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢提供有用的错误/消息,我也想为 static_assert 这样做。问题是,它们依赖于模板参数。通常,这些参数将由于引起的错误而在路上或另一个上显示,但是它们是模糊的或不分组的,因此它们是有意义的。示例:

 模板< class T& 
struct fake_dependency {
static bool const value = false;
};

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

template< class OtherTag>
Foo(Foo static_assert(fake_dependency< T> :: value,Can not 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):错误C2338:无法创建Foo< T, from Foo< T,OtherTag> ;. 
src\main.cpp(84):参见对函数模板实例化的引用'Foo :: Foo
(const Foo & '正在编译
with
[
T = int,
Tag = main :: TagB
]

一个标签在功能模板本身中提到,另一个标签在类模板中。不是那么好。让我们看看 GCC输出

  prog.cpp:在构造函数'Foo< T,Tag> :: Foo(const Foo< T,OtherTag>&)[With OtherTag = main():: TagA,T = int,Tag = main ]':
prog.cpp:18:32:从这里实例化
prog.cpp:12:5:error:static assertion failed:无法从Foo< T创建Foo< T,Tag& OtherTag> ;.。

更好,但仍然不是 static_assert 是。现在想象一些更多的参数,或更多的模板,或两者。



解决方法之一是使用中间结构,将两个标签都作为模板参数:

 模板< class Tag,class OtherTag> 
struct static_Foo_assert {
static_assert(fake_dependency< Tag> :: value,无法从Foo< T,OtherTag>创建Foo< T,Tag&
};

模板< 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:无法创建Foo< T,Tag> from Foo< T,OtherTag> ;. 
src \main.cpp(79):参见类模板实例化的参考'static_Foo_assert< Tag,OtherTag>'被编译
with
[
Tag = main :: TagB ,
OtherTag = main :: TagA
]

以下是 GCC说的内容:

  .cpp:在'static_Foo_assert< main():: TagB,main():: TagA>'的实例化中:
prog.cpp:17:40:从Foo< T,Tag> :: Foo const Foo< T,OtherTag>&)[with OtherTag = main():: TagA,T = int,Tag = main():: TagB]'
prog.cpp:23:32:
prog.cpp:8:5:error:static assertion failed:无法从Foo< T,OtherTag>创建Foo< T,Tag&

看起来不错。问题:我需要为每个模板创建这样的结构,因为 static_assert 中的错误消息需要是一个字符串文字...



现在,对于我的问题:我们可以直接包含类型名称到 static_assert ?喜欢

  static_assert(...,无法从Foo<T创建Foo<T,Tag> ,OtherTag> ;.); 

输出示例:


无法创建 Foo Foo


或者,如果这不可能实现,我们可以使错误消息成为一个额外的模板参数,

代码:



 模板< 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

用法:



  //用于显示零件的缩进
static_assert(
AssertValue<
std :: my_check<
T0,decltype(* somethingComplicated),T7 :: value_type
>
>,
发生可怕的事
);

其中 std :: my_check< ...> :: value 是检查的布尔结果



示例



=http://sscce.org> SSCCE 示例参见: IDEOne示例



示例的错误信息:

  prog.cpp:在AssertValue< std :: is_base_of& IMyInterface,MyBadType> >':
prog.cpp:37:69:从'void MyFunction(IteratorType,IteratorType)实例化IteratorType = __gnu_cxx :: __ normal_iterator< MyBadType *,std :: vector< MyBadType> >]'
prog.cpp:60:38:从这里实例化
prog.cpp:9:5:error:static assertion failed:Assertion failed<
prog.cpp:In function'void MyFunction(IteratorType,IteratorType)[with IteratorType = __gnu_cxx :: __ normal_iterator< MyBadType *,std :: vector< MyBadType> >]':
prog.cpp:60:38:从这里实例化
prog.cpp:39:5:error:static assertion failed:iterator passed不引用IMyInterface项



说明



如果断言失败, AssertValue的模板参数,因此打印检查的完整模板扩展。例如,如果您检查 std :: is_base_of ,它将打印完整类型的检查,例如: std :: is_base_of< IMyInterface, MyBadType>



唯一的问题是,这只适用于将结果放在中的模板: :value 。但 type_traits 大多使用这个,是goto标准。


I like to give helpful errors / messages, and I also want to do so for my static_asserts. The problem is, that they depend on template parameters. Normally, those parameters will get displayed on way or an other due to the error raised, but they are either obscure or not grouped so they make sense. Example:

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);
}

Output on 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
          ]

One tag is mentioned in the function template itself, the other below with the class template. Not so nice. Lets see what GCC outputs:

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>."

Much better, but still not really where the static_assert is. And now imagine some more parameters, or more templates, or both. shivers

One way to work around that is to use an intermediate struct, which takes both Tags as template parameters:

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;
  }
};

Now lets see the output again:

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
          ]

Much better! Here's what GCC says:

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>."

Looks not bad. The problem: I need to create such a struct for every template, since the error message in static_assert needs to be a string literal...

Now, for my question: Can we somehow include the type names directly into the static_assert? Like

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

Example output:

Cannot create Foo<int,main::TagA> from Foo<int,main::TagB>.

Or, if that isn't achievable, can we somehow make the error message an extra template parameter, as to make it passable?

解决方案

My Hack

Code:

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;
};

It allows for you to check any ::value assertion and dump the types if it failed.

Usage:

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

where std::my_check<...>::value is the boolean result of the check

Example

For a full SSCCE example see: IDEOne Example

The Example's error message:

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"

Explanation

If the assertion fails, it will print the template arguments of AssertValue and therefore print the full template expansion of your check. For example, if you were checking a std::is_base_of it will print the full type of the check, e.g.: std::is_base_of<IMyInterface, MyBadType>. Then you know exactly what types were used in the failed assertion.

The only problem is that this only works on templates that put their result in ::value. However type_traits mostly uses this and is the goto standard.

这篇关于在static_assert输出中集成类型名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆