使用enable_if对其模板成员函数进行单独的定义和声明,其模板参数还包含constexpr成员函数 [英] Separate definition and declaration of template member function using enable_if whose template parameter also includes a constexpr member function

查看:294
本文介绍了使用enable_if对其模板成员函数进行单独的定义和声明,其模板参数还包含constexpr成员函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下内容在CentOS 7上的g ++ 8.1.0下无法编译:

The following doesn't compile under g++ 8.1.0 on CentOS 7:

嘿.h

#pragma once
#include <iostream>
#include <type_traits>

class Valid {};
class Invalid {};

struct Hey
{
  template<typename T>
  static constexpr bool is_valid() { return std::is_same_v<T, Valid>; }

  template<typename T, std::enable_if_t<is_valid<T>()>* = nullptr>
    void howdy() const;
};

template<typename T, std::enable_if_t<Hey::is_valid<T>()>*>
  void Hey::howdy() const
{
  std::cout << "Howdy" << std::endl;
}

编译器输出:

In file included from hey.cpp:1:
hey.h:18:8: error: no declaration matches ‘void Hey::howdy() const’
   void Hey::howdy() const
        ^~~
hey.h:14:10: note: candidate is: ‘template<class T, std::enable_if_t<is_valid<T>()>* <anonymous> > void Hey::howdy() const’
     void howdy() const;
          ^~~~~
hey.h:8:8: note: ‘struct Hey’ defined here
 struct Hey
        ^~~

令人惊讶的是,为了正确编译并获得所需的行为,我要做的就是在Hey中添加typedef:

Amazingly, all I have to do to both compile correctly and get the desired behavior is add a typedef in Hey:

hey.h(固定,跳过了无聊的前几行)

struct Hey
{
  template<typename T>
  static constexpr bool is_valid() { return std::is_same_v<T, Valid>; }

  template<typename T>
  using EnableType = std::enable_if_t<is_valid<T>()>;

  template<typename T, EnableType<T>* = nullptr>
    void howdy() const;
};

template<typename T, Hey::EnableType<T>*>
  void Hey::howdy() const
{
  std::cout << "Howdy" << std::endl;
}

hey.cpp

#include "hey.h"

int main(int, char**)
{
  Hey hey;
  hey.howdy<Valid>();

  // Adding this line breaks the build, as it should:
  // hey.howdy<Invalid>();

  return 0;
}

经过多次调整后,我将编译器错误情况缩小为1) is_valid()的成员,以及2) howdy()的体内声明,但在外部定义。如果您使用删除,并使 is_valid() Hey ,没有编译问题。如果使用删除并在类定义中定义 howdy(),那么编译也不会出现问题。但是,如果在类定义之外定义了 howdy(),则在类定义中声明了 is_valid(),并且 using 不存在,编译器将失败。这是正确的行为吗?我在查看编译器错误吗?

After many tweaks, I've narrowed the compiler error situation to the fact that 1) is_valid() is a member of Hey and 2) howdy() is declared inside Hey's body but defined outside. If you delete the using and make is_valid() a standalone function outside of Hey, there are no issues compiling. If you delete the using and define howdy() inside the class definition, there are also no issue compiling. But when howdy() is defined outside of the class definition, is_valid() is declared inside of the class definition, and the using isn't present, the compiler fails. Is this correct behavior? Am I looking at a compiler bug?

推荐答案

模板声明中表达式的匹配基于 等效性 ,基于该概念-定义规则。为了使两个表达式等效,它们必须至少是逐个标记地相同,且模板参数的重命名是相同的。

The matching of expressions in template declarations is based on equivalence, a concept based on the one-definition rule. For two expressions to be considered equivalent, they must be at least token-by-token identical modulo the renaming of template parameters.

表达式 is_valid< T>() Hey :: is_valid< T& ()不等效(第二个有两个令牌,第一个没有两个令牌),因此不需要编译器匹配它们。

The expressions is_valid<T>() and Hey::is_valid<T>() are not equivalent (the second has two tokens the first doesn't have), and so the compiler is not required to match them.

Hey :: EnableType< T> 是一种类型,不受严格的表达式等价规则约束。

Hey::EnableType<T> is a type, and is not subject to the strict equivalence rules for expressions.

这篇关于使用enable_if对其模板成员函数进行单独的定义和声明,其模板参数还包含constexpr成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆