繁体   English   中英

在static_assert输出中集成类型名称?

[英]Integrate type name in static_assert output?

我想提供有用的错误/消息,我也想为我的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
          ]

函数模板本身提到了一个标记,下面是类模板。 不太好。 让我们看看海湾合作委员会的成果

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真正原因。 现在想象一些更多参数,或更多模板,或两者兼而有之。 不寒而栗

解决这个问题的一种方法是使用一个中间结构,它将两个标记作为模板参数:

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
          ]

好多了! 以下是海湾合作委员会的说法

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::TagB>创建Foo<int,main::TagA> Foo<int,main::TagB>

或者,如果这是不可实现的,我们可以以某种方式使错误消息成为额外的模板参数,以使其可通过吗?

我的哈克

码:

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主要使用它并且是goto标准。

可以将一个字符串文字作为模板非类型参数传入,只需要一点跳跃 但是由于static_assert的第二个参数被约束为字符串文字而不是地址常量表达式,所以遗憾的是这并没有多大用处。

可悲的是,我怀疑你最好的选择是游说委员会或编译器编写者来扩展设施。

如果您的编译器提供__FUNCTION__宏,您可以使用它和文字串联进行非常简单的替换。 但是,gcc和clang的实现不是作为宏完成的,所以这个解决方案对它们不起作用。

#include "stdafx.h"
#include <type_traits>

template <class T>
class must_be_pod
{
    static void test() { static_assert (std::is_pod<T>::value, __FUNCTION__ ": not a POD"); }
public:
    must_be_pod() { test(); }
};

class not_a_pod
{
public:
    not_a_pod() {}
    virtual ~not_a_pod() {}
};

int main()
{
    must_be_pod<not_a_pod> should_fail; // and it does
    return 0;
}

这由VS2015编译时产生以下输出:

static_assert_test.cpp(10): error C2338: must_be_pod<class not_a_pod>::test: not a POD

我看到这已经回答了一段时间,但完整的答案丢失了,我找到了一种非常简单的方法来达到预期的效果。

template <typename T, bool value>
static typename std::enable_if<value, void>::type FunctionWithReadableErrorMessage()
{
}


int  main()
{
    FunctionWithReadableErrorMessage<int, false>();
    return 0;
}

如果value = true,此函数将编译并且无效,否则我们会收到以下错误消息:

main.cpp:在函数'int main()'中:main.cpp:16:50:错误:没有匹配函数来调用'FunctionWithReadableErrorMessage()'FunctionWithReadableErrorMessage(); ^

如果我们想要更一般,我们可以把它放在一个宏

std::type_info有一个成员const char* name()

#include <typeinfo>
using namespace std;

//...

const char* name = type_info(T).name();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM