调用 static_assert(false) 的正确方法是什么?
What's the right way to call static_assert(false)?
我正在尝试使用 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]);
}
根据 [temp.res]/8(重点是我的):
Knowing which names are type names allows the syntax of every template
to be checked. The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the
template is not instantiated, or (...)
依靠矛盾确实不是最好的,但有一个更简单的方法:
template <class...>
struct False : std::bool_constant<false> { };
template <class T>
void bang() {
static_assert(False<T>{}, "bang!");
}
为什么这不属于 "no valid specialization" 案例?
好吧,因为您 可以 实际上进行有效的专业化,代码的后半部分:
template <>
struct False<int> : std::bool_constant<true> { };
int main() {
bang<int>(); // No "bang"!
}
当然,实际上没有人会专门研究 False
来破坏您在真实代码中的断言,但这是可能的:)
没有办法做到这一点。您也许能够使其在您的编译器上运行,但生成的程序格式错误,无需诊断。
使用=delete
.
template< class T >
void marshal(std::string name, T *value) = delete;
我一开始不明白你为什么有 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;
}
我正在尝试使用 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]);
}
根据 [temp.res]/8(重点是我的):
Knowing which names are type names allows the syntax of every template to be checked. The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or (...)
依靠矛盾确实不是最好的,但有一个更简单的方法:
template <class...>
struct False : std::bool_constant<false> { };
template <class T>
void bang() {
static_assert(False<T>{}, "bang!");
}
为什么这不属于 "no valid specialization" 案例?
好吧,因为您 可以 实际上进行有效的专业化,代码的后半部分:
template <>
struct False<int> : std::bool_constant<true> { };
int main() {
bang<int>(); // No "bang"!
}
当然,实际上没有人会专门研究 False
来破坏您在真实代码中的断言,但这是可能的:)
没有办法做到这一点。您也许能够使其在您的编译器上运行,但生成的程序格式错误,无需诊断。
使用=delete
.
template< class T >
void marshal(std::string name, T *value) = delete;
我一开始不明白你为什么有 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;
}