具有类型模板参数默认值的非类型模板参数

Emb*_*eer 8 c++ templates c++14

我有以下代码:

#include <iostream>
#include <string>
#include <type_traits>

struct Foo
{
   int i;
   int j;
};

template<typename T, T DEFAULT>
class Bar
{
public:
    Bar(): mVal(DEFAULT)
    {
        std::cout << "Bar constructor with mVal = " << mVal << "\n";
    }
    
    ~Bar(){}
    
    Bar(const T &i) : mVal(i)
    {
        std::cout << "Bar constructor with mVal = " << mVal << "\n";
    }
    
    Bar &operator=(T const &val)
    {
        mVal = val;
        std::cout << "Bar assignment operator with mVal = " << mVal << "\n";
        return *this;
    }
    
    explicit operator T() const
    {
        return mVal;
    }

private:
    T mVal;
};



int main()
{
  std::cout << "Hello \n";
  
  Bar<int, 10> bar1;
}
Run Code Online (Sandbox Code Playgroud)

只要第一个模板参数Bar是整数类型,这在 gcc C++14 中就可以正常工作。如果我想做Bar<Foo, {}>下面的错误信息打印:

on-type template parameters of class type only available with '-std=c++2a' or '-std=gnu++2a'
Run Code Online (Sandbox Code Playgroud)

我已经预料到了。更改template<typename T, T DEFAULT> class Bartemplate<typename T, T DEFAULT = {}> class Bar导致相同的错误。template<typename T> class Bar<T, {}>出于同样的原因,模板专业化也不起作用。

我也尝试过,std::enable_if_t<std::is_integral<T>::value>但找不到可行的解决方案。

是否有任何可能的方式来只写Bar<Foo>,而不必像写一个单独的类template<typename T, T DEFAULT> class BarDefault,并template<typename T> class Bar为它?

Mar*_*k R 5

模板参数和模板参数 - cppreference.com

非类型模板参数必须具有结构类型,它是以下类型之一(可选 cv 限定,限定符被忽略):

  • 左值引用类型(对象或函数);

  • 整型;

  • 指针类型(指向对象或函数);

  • 指向成员类型(指向成员对象或成员函数)的指针;

  • 枚举类型

  • std::nullptr_t;(自 C++11 起)

  • 浮点类型;

  • 具有以下属性的文字类类型:

  • 所有基类和非静态数据成员都是公共且不可变的

  • 所有基类和非静态数据成员的类型都是结构类型或其(可能是多维)数组。(自 C++20 起)

因此,从 c++20 开始,基本上可以使用自定义结构作为模板值参数。

演示

您可以通过提供依赖于哪个作业提供默认值的模板来解决此问题:

https://godbolt.org/z/RFp_xH

#include <iostream>
#include <string>
#include <type_traits>

struct Foo
{
   int i = 42;
   int j = 4;
};

std::ostream& operator<<(std::ostream& out, const Foo& a)
{
    return out << a.i << ',' << a.j;
}

template<typename T>
struct BarDefaultValue
{
    constexpr static T value()
    {
        return T{};
    }
};

template<>
struct BarDefaultValue<int>
{
    constexpr static int value()
    {
        return 42;
    }
};

template<typename T, typename D = BarDefaultValue<T>>
class Bar
{
public:
    Bar(): mVal(D::value())
    {
        std::cout << "Bar constructor with mVal = " << mVal << "\n";
    }
    
    ~Bar(){}
    
    Bar(const T &i) : mVal(i)
    {
        std::cout << "Bar constructor with mVal = " << mVal << "\n";
    }
    
    Bar &operator=(T const &val)
    {
        mVal = val;
        std::cout << "Bar assignment operator with mVal = " << mVal << "\n";
        return *this;
    }
    
    explicit operator T() const
    {
        return mVal;
    }

private:
    T mVal;
};

int main()
{
  std::cout << "Hello \n";
  
  Bar<int> bar1;
  Bar<Foo> bar2;
}
Run Code Online (Sandbox Code Playgroud)


dar*_*une 0

您可以设置一个默认值来提供。

template<class T>
constexpr T brace_init_value{};
Run Code Online (Sandbox Code Playgroud)

然后用作:

template<typename T, T DEFAULT = brace_init_value<T> >
class Bar
{
Run Code Online (Sandbox Code Playgroud)