C ++实现了我自己的static_assert

时间:2016-10-27 00:53:05

标签: c++ c++11 templates static-assert

作为一个学习项目,我正在编写自己的模板元编程static_assert。我在网上发现了一个元编程技巧:尝试创建一个大小为0的数组,这将无法编译。因此,我使用两种几乎相同的方法:在Visual Studio上,一种是有效的,另一种是不起作用的,但我不明白它们的区别。在g ++ 5.4.0上,它们都不起作用(甚至没有" -std = c ++ 14"标志)。为什么不呢?

//This correctly aborts the compile on Visual Studio 2015. 
//But on g++ it doesn't work (not even with the "-std=c++14" flag) .
template <bool b>
inline void my_static_assert_function()
{
    char member[b]; //if b is false, this is 0-length and fails to compile. 
}

//On Visual Studio 2015, this does give a warning, but does not
//abort the compile. Why not? It seems virtually identical to the
//previous one. And on g++, it doesn't even warn. 
template <bool b>
struct my_static_assert_struct
{
    char member[b]; //if b is false, this *warns* but compiles.
};

int main()
{
    my_static_assert_function<1 == 2>(); //This aborts the compile, great.
    my_static_assert_struct<1 == 2> c; //This does NOT abort the compile???
}

问题#1 - 为什么&#34; g ++ -std = c ++ 14 main.cpp&#34;允许这个甚至没有警告编译? my_static_assert_function不应该在那里工作吗?我在ubuntu上使用5.4.0。

问题#2 - 在Visual Studio 2015上,my_static_assert_function无法编译,但my_static_assert_struct只是编译警告。但是有什么区别?如果对方没有办法,怎么办?

1 个答案:

答案 0 :(得分:2)

正如@Kerrek SB在评论中所提到的,gcc使用了一些非标准的ISO C ++扩展来允许零大小的数组,尽管它会给你一个警告。一个更优雅的选择是通过SFINAE std::enable_if false Live on Coliru,就像这样

#include <iostream>
#include <type_traits>

template<bool b, typename std::enable_if<b>::type* = nullptr>
void my_static_assert() 
{
    std::cout << "Assertion OK\n";
}

int main()
{
    my_static_assert < (1 < 2) > (); // ok
    //my_static_assert < (1 > 2) > (); // fails to compile
}

Andrei Alexandrescu

另一个替代方案(我认为首先由Live on Coliru提出)是保留一个非定义的通用模板,并仅定义true专门化。然后,如果您尝试实例化false特化,则会出现编译时错误,因为您无法实例化不完整的类型。示例如下:

template<bool> // generic
struct my_static_assert;

template<>
struct my_static_assert<true>{};

int main()
{
    my_static_assert < (1 < 2) >{}; // ok
    my_static_assert < (1 > 2) >{}; // fails to compile
}

kron