c++ - 使用 enable_if 单独定义和声明模板成员函数,其模板参数还包含一个 constexpr 成员函数

标签 c++ c++11 sfinae

以下代码无法在 CentOS 7 上的 g++ 8.1.0 下编译:

嘿.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:

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()Hey 的成员和 2) howdy ()Hey 的主体内声明,但在外部定义。如果您删除 using 并使 is_valid() 成为 Hey 之外的独立函数,则编译没有问题。如果您删除 using 并在类定义中定义 howdy() ,编译也没有问题。但是当 howdy() 在类定义之外定义时,is_valid() 在类定义内部声明,并且 using 不是目前,编译器失败。这是正确的行为吗?我在看编译器错误吗?

最佳答案

模板声明中表达式的匹配是基于equivalence ,一个基于单一定义规则的概念。对于被认为是等价的两个表达式,它们必须至少是逐个 token 相同的模版参数重命名模数。

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

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

关于c++ - 使用 enable_if 单独定义和声明模板成员函数,其模板参数还包含一个 constexpr 成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51756936/

相关文章:

c++ - SFINAE 在返回类型中工作但不作为模板参数

c++ - 无法在 VS 2015 中编译 CUDA 代码

c++调用c函数,如果它确实存在

c++ - 为什么 boost::enable_if 不会导致重复重载方法编译错误

windows - Windows 上的 C++11 线程

c++ - 排列参数包中的参数

c++ - 如何在不同线程中随机播种

python - 使用 Tensorflow C++ API 执行在 skflow 中训练的模型

c++ - 如何将 Dart_Handle 列表转换为 C++ 数组?

c++ - 不在 VS 上运行,但在 Dev C++ 上运行