【问题标题】:Template non-type parameter with different types不同类型的模板非类型参数
【发布时间】:2019-04-23 01:58:41
【问题描述】:

假设输入模板参数T 可能有也可能没有内部变量bar。我正在尝试编写一个结构,当我们拥有它时返回 bar 的值,并在我们没有时返回一些常量。这是我的尝试:

struct A {
  static constexpr unsgined int bar = 20;
  hasBar = true;
};

struct B {
  hasBar = false;
};

template <typename T, typename std::enable_if<T::hasBar, int>::type>
struct getBar {
  static constexpr unsigned int bar = T::bar;
};

template <typename T, typename std::enable_if<!T::hasBar, int>::type>
struct getBar {
  static constexpr unsigned int bar = 0;
};

int main() {
  getBar<A>::bar; // Expect 20
  getBar<B>::bar; //Expect 0
}

我无法使用 C++14 编译此代码。编译器报错:“模板非类型参数有不同的类型”。

为什么会出现这样的错误,我该如何解决?

【问题讨论】:

标签: c++ templates c++14 template-meta-programming sfinae


【解决方案1】:

类模板不能重载(如函数模板);您可以改用specialization。例如

template <typename T, typename = void>
struct getBar {
  static constexpr unsigned int bar = 0;
};

template <typename T>
struct getBar<T, std::enable_if_t<T::hasBar>> {
  static constexpr unsigned int bar = T::bar;
};

LIVE

【讨论】:

    【解决方案2】:

    可以直接检测::bar是否存在,不需要hasbar

    类似...

    #include <type_traits>
    #include <iostream>
    struct A {
      static constexpr unsigned int bar = 20;
    
    };
    
    struct B {
    
    };
    
    
    template <typename T,typename=void>
    struct getBar {
      static constexpr unsigned int bar = 0;
    };
    
    template <typename T>
    struct getBar<T,std::void_t<decltype(T::bar)>> {
      static constexpr unsigned int bar =  T::bar;
    };
    
    int main() {
      std::cout << getBar<A>::bar << std::endl; // Expect 20
      std::cout << getBar<B>::bar << std::endl; //Expect 0
    }
    

    Demo

    【讨论】:

    • 绝妙的解决方案!
    【解决方案3】:

    另一种不需要hasBar而只需检测bar的存在的解决方案(如果与int不同,还保持bar的原始类型)

    struct A
     { static constexpr unsigned int bar = 20; };
    
    struct B
     { };
    
    template <typename T>
    constexpr auto getBarHelper (int) -> decltype( T::bar )
     { return T::bar; }
    
    template <typename T>
    constexpr int getBarHelper (long)
     { return 0; }
    
    template <typename T>
    struct getBar
     { static constexpr auto bar { getBarHelper<T>(0) }; };
    
    int main()
     {
       static_assert( 20u == getBar<A>::bar, "!" );
       static_assert(  0  == getBar<B>::bar, "!" );
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-24
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      相关资源
      最近更新 更多