关于这个主题,我读了一些相关的SO问题/解答/评论。仅找到一个相关但有些隐晦的问题/答案here。请允许我尝试以问题/答案的方式清楚地显示问题。为了他人的利益。
让代码说话。想象您设计了这个模板。
// value holder V1.0
// T must not be reference or array or both
template<typename T> struct no_arrf_naive
{
static_assert(!std::is_reference_v<T>, "\n\nNo references!\n\n");
static_assert(!std::is_array_v<T>, "\n\nNo arrays!\n\n");
using value_type = T;
T value;
};
一个人可能会认为它简单又安全。一段时间后,其他人采用了这个复杂的大型API,并将其深埋在其中,然后开始使用它。上面的结构很深。通常,他们只是使用它而无需查看背后的代码。
using arf = int(&)[3];
using naivete = no_arrf_naive<arf>;
// the "test" works
constexpr bool is_ok_type = std::is_class_v< naivete >;
// this declaration will also "work"
void important ( naivete ) ;
但是。实例化不起作用
naivete no_compile;
静态断言消息确实突然显示。但是“测试”如何编译和通过的呢?这是怎么回事?
答案 0 :(得分:1)
问题是API错误。作为类成员的static_assert会“插入”,但不会在实例化之前执行。
首先对有问题的API进行了评论
template<typename T>
struct no_arrf_naive
{
// member declarations
// used only on implicit instantiation
// https://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation
static_assert(!std::is_reference_v<T>, "\n\nNo references!\n\n");
static_assert(!std::is_array_v<T>, "\n\nNo arrays!\n\n");
using value_type = T;
T value;
};
用户在此处进行了适当的编码,以从模板转换为类型,但是,static_assert的功能不起作用:
using naivete = no_arrf_naive<arf>;
最令人担忧的是,直到有人想要使用此功能时,它才会被忽略。那将不会编译,API作者放置在其中的消息将最终显示。但是a,为时已晚。
在使用某些大型C ++源代码工作的项目中,最晚出现的问题是最臭名昭著的问题。
解决方案是旧的SFINAE。修复的API是这样的:
// value holder
// references or arrays or both are excluded at compile time
template<typename T,
std::enable_if_t<
(!std::is_reference_v<T> && !std::is_array_v<T>), bool> = true
> struct no_arrf
{
using value_type = T;
T value;
};
在尝试使用具有引用或数组或两者兼有的模板创建类型时,以上内容不会立即编译:
// reference to array of three int's
using arf = int(&)[3] ;
// no can do
using no_naivete = no_arrf<arf>;
(MSVC) error C2972: 'no_arrf':
template parameter 'unnamed-parameter':
the type of non-type argument is invalid
我认为整个故事看起来有些琐碎,甚至对某些人来说毫无用处。但是,我敢肯定,很多优秀的人都会来这里寻求急需的标准C ++建议。对于他们来说,这既不平凡也不无用。
非常感谢您阅读。