调用static_assert(false)的正确方法是什么?

时间:2017-05-19 00:14:01

标签: c++11 sfinae static-assert

我正在尝试使用static_assert来强制失败。如果您尝试以特定方式实例化特定的模板化函数,我想生成编译器错误。我可以使它工作,但它真的很难看。有更简单的方法吗?

这是我的第一次尝试。这根本不起作用。它总是会产生错误,即使没有人试图使用此功能。

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

这是我的第二次尝试。它确实有效。如果你不打电话,你就不会有错误。如果您这样做,您会得到一条非常易读的错误消息,指向此行并指向试图实例化它的代码。

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

问题是这段代码充其量是丑陋的。它看起来像一个黑客。我担心下次更改优化级别,升级编译器,打喷嚏等时,编译器会意识到第二种情况与第一种情况相同,它们都会停止工作。

有没有更好的方法来做我想做的事情?

这是一些背景信息。我想有几个不同版本的marshal(),它们适用于不同的输入类型。我想要一个使用模板作为默认情况的版本。我想要另一个特别禁止除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]);
}

4 个答案:

答案 0 :(得分:6)

没有办法做到这一点。您可能能够在编译器上运行它,但生成的程序生成错误,无需诊断。

使用=delete

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

答案 1 :(得分:2)

根据[temp.res]/8(强调我的),你要做的事情是注定要形成不良(甚至你的解决方法也会失败):

  

知道哪些名称是类型名称允许每个模板的语法   被检查。 该程序格式错误,无需诊断,如果
    - 无法为模板生成有效的专业化,也无法在模板中生成constexpr if语句的子语句   模板未实例化,或(...)

答案 2 :(得分: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来破坏你在实际代码中的断言,但它有可能:)

答案 3 :(得分:1)

我不明白你为什么首先template< class T > void marshal(std::string name, T *value)。这应该只是主模板中的static_assert。

也就是说,您应该将主模板的定义更改为

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