C++11 什么';调用静态断言(false)的正确方法是什么?

C++11 什么';调用静态断言(false)的正确方法是什么?,c++11,sfinae,static-assert,C++11,Sfinae,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(false, "You cannot marshal a pointer.");
}
模板
无效封送处理(标准::字符串名称,T*值)
{
static_assert(false,“无法封送指针”);
}
这是我的第二次尝试。它确实有效。如果不调用此函数,则不会出错。如果调用它,您会得到一条可读性很强的错误消息,它指向这一行,并指向试图实例化它的代码

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.");
}
模板
无效封送处理(标准::字符串名称,T*值)
{
静态断言(std::is_pod::value&!std::is_pod::value,“您不能封送指针”);
}
问题是,这段代码充其量是丑陋的。它看起来像一个黑客。我担心下次我更改优化级别、升级编译器、打喷嚏等时,编译器会意识到第二种情况与第一种情况相同,它们都将停止工作

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

这里有一些背景。我想要几个不同版本的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]);
}
void封送处理(std::string name,std::string)
{ 

std::cout根据(我的重点)的说法,你试图做的事情注定是不正确的(甚至你的变通方法也可能失败):

知道哪些名称是类型名称可以使用每个模板的语法 待检查。程序格式不正确,无需诊断,如果
-无法为模板中的模板或constexpr if语句的子语句生成有效的专门化,并且 模板未实例化,或(…)


根据(我的重点),您试图做的事情注定是不正确的(即使您的变通方法也可能失败):

知道哪些名称是类型名称可以使用每个模板的语法 待检查。程序格式不正确,无需诊断,如果
-无法为模板中的模板或constexpr if语句的子语句生成有效的专门化,并且 模板未实例化,或(…)


依靠矛盾确实不是最好的,但有一个更简单的方法:

template <class...>
struct False : std::bool_constant<false> { };

template <class T>
void bang() {
    static_assert(False<T>{}, "bang!");
}
模板
struct False:std::bool_常量{};
样板
void bang(){
静态断言(False{},“bang!”);
}
为什么这不属于“无有效专业化”的情况 好吧,因为你实际上可以用代码的后半部分进行有效的专门化:

template <>
struct False<int> : std::bool_constant<true> { };

int main() {
    bang<int>(); // No "bang"!
}
模板
struct False:std::bool_常量{};
int main(){
砰();//没有“砰”!
}

当然,实际上没有人会专门化
False
来破坏真实代码中的断言,但这是可能的:)

依赖矛盾确实不是最好的,但有一种更简单的方法:

template <class...>
struct False : std::bool_constant<false> { };

template <class T>
void bang() {
    static_assert(False<T>{}, "bang!");
}
模板
struct False:std::bool_常量{};
样板
void bang(){
静态断言(False{},“bang!”);
}
为什么这不属于“无有效专业化”的情况 好吧,因为你实际上可以用代码的后半部分进行有效的专门化:

template <>
struct False<int> : std::bool_constant<true> { };

int main() {
    bang<int>(); // No "bang"!
}
模板
struct False:std::bool_常量{};
int main(){
砰();//没有“砰”!
}

当然,实际上没有人会专门化
False
来破坏真实代码中的断言,但这是可能的:)

没有办法做到这一点。您可以让它在编译器上工作,但生成的程序格式不正确,不需要诊断

使用
=删除

template< class T >
void marshal(std::string name, T  *value) = delete;
模板
无效封送处理(std::string name,T*value)=删除;

无法做到这一点。您可以在编译器上运行它,但生成的程序格式不正确,不需要进行诊断

使用
=删除

template< class T >
void marshal(std::string name, T  *value) = delete;
模板
无效封送处理(std::string name,T*value)=删除;

我不明白为什么您首先要使用
模板无效封送(std::string name,t*value)
。这应该只是主模板中的静态断言

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

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;
}
模板
无效封送处理(标准::字符串名称,T值)
{
静态_断言(std::is_pod::value);
静态_断言(!std::is_指针::值);

std::cout我不明白为什么您首先使用
模板无效封送(std::string name,t*value)
。这应该只是主模板中的静态断言

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

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;
}
模板
无效封送处理(标准::字符串名称,T值)
{
静态_断言(std::is_pod::value);
静态_断言(!std::is_指针::值);

如果编译器知道没有有效的专门化(即,
False
永远不会专门化,因为它有您的源代码),那么它不是证明你的程序格式不正确吗?不需要诊断吗?即,你确定这会避免该规则,还是只是让它更难被注意?@Yakk我认为这是在延伸它。
False
可以专门化。它不在当前程序中不在该要点AFAICT的范围内。如果我动态地不同意呢d另一个二进制文件具有专门化的
False
,这会使我的程序再次形成良好的格式吗?那么,你不确定吗?我得到了希望能够静态断言的合理性