代码之家  ›  专栏  ›  技术社区  ›  Zark Bardoo

如果模板参数还包括constexpr成员函数,则使用enable_分隔模板成员函数的定义和声明

  •  3
  • Zark Bardoo  · 技术社区  · 8 年前

    以下代码在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:

    嘿.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;
    }
    

    嘿,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() 在内部声明 嘿 的身体,但定义在外面。如果删除 using 使 是否有效() 外部的独立函数 嘿 ,编译时没有问题。如果删除 使用 并定义 你好() 在类定义中,编译也没有问题。但是当 你好() 在类定义之外定义, 是否有效() 在类定义内声明,并且 使用 不存在,编译器将失败。这是正确的行为吗?我在看编译器错误吗?

    1 回复  |  直到 8 年前
        1
  •  2
  •   T.C. Yksisarvinen    8 年前

    模板声明中表达式的匹配基于 equivalence ,基于一个定义规则的概念。若要将两个表达式视为等效表达式,则它们必须至少是逐标记完全相同的,以模拟模板参数的重命名。

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

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