非型模板参数,构造函数和扣除指南

Non-type template parameters, constructor and deduction guide

本文关键字:构造函数 参数 非型      更新时间:2023-10-16

我想拥有一个结构模板,该模板是由其组件的特定值在构造过程中传递给其的特定值,这样不同的值会创建不同的C 数据类型,并思考非类型模板参数可能对此有用。像这样的东西(只是一个简单的示例来显示问题,实际结构将更加复杂):

enum ElementType
{
    TYPE1,
    TYPE2
};
template<ElementType elementType, int size>
struct DataType
{
    DataType(ElementType et = elementType, int s = size):
        elementType_(et),
        size_(s)
    {
    }
    ElementType elementType_;
    int size_;
};
int main()
{
    auto d1 = DataType(ElementType::TYPE1, 1);
}

我尝试使用G -8 -STD = C 17构建此问题,这给了我以下错误:

./main.cpp:23:42: error: class template argument deduction failed:
auto d1 = DataType(ElementType::TYPE1, 1);
                                      ^
../main.cpp:23:42: error: no matching function for call to     ‘DataType(ElementType, int)’
../main.cpp:12:2: note: candidate: ‘template<ElementType elementType, int size> DataType(ElementType, int)-> DataType<elementType, size>’
  DataType(ElementType et = elementType, int s = size):
  ^~~~~~~~
../main.cpp:12:2: note:   template argument deduction/substitution failed:
../main.cpp:23:42: note:   couldn't deduce template parameter ‘elementType’
  auto d1 = DataType(ElementType::TYPE1, 1);
                                      ^
../main.cpp:23:42: error: expression list treated as compound expression in functional cast [-fpermissive]
../main.cpp:23:42: warning: left operand of comma operator has no effect [-Wunused-value]

请注意,我不能使用类型的模板参数,因为两种类型的参数是固定的(ElementTypeint),但是DataType(ElementType::TYPE1, 1)必须与DataType(ElementType::TYPE1, 2)不同类型,并且DataType(ElementType::TYPE1, 1)必须与DataType(ElementType::TYPE2, 1)不同。

您可以这样定义模板:

template<ElementType elementType, int size>
struct DataType
{
    const ElementType elementType_ = elementType;
    const int size_ = size;
};

并创建这样的实例:

auto d1 = DataType<ElementType::TYPE1, 1>();

demo

要使用推论,您传递给构造函数的值需要是恒定的表达式。不幸的是,值以参数为单位的constexpr属性传递。为了防止这种行为,您可以传递包含类型的值,例如使用std::integral_constant

示例用法:

#include <type_traits>
enum ElementType
{
    TYPE1,
    TYPE2
};
template<ElementType elementType, int size>
struct DataType
{
    DataType(std::integral_constant<ElementType, elementType>, std::integral_constant<int, size> ic):
        elementType_(elementType),
        size_(ic)
    {
    }
    ElementType elementType_;
    int size_;
};
int main()
{
    auto d1 = DataType(std::integral_constant<ElementType, TYPE1>{}, std::integral_constant<int, 1>{});
}

[live demo]

为了使使用更方便您可以与Constexpr后缀操作员周围的整体const:

#include <type_traits>
enum ElementType
{
    TYPE1,
    TYPE2
};

template <class... Ts>
constexpr int ival(Ts... Vs) {
    char vals[sizeof...(Vs)] = {Vs...};
    int result = 0;
    for (int i = 0; i < sizeof...(Vs); i++) {
        result *= 10;
        result += vals[i] - '0';
    }
    return result;
}
template <class T, class... Ts>
constexpr ElementType etval(T V, Ts... Vs) {
    if (V == '1')
       return TYPE1;
    if (V == '2')
       return TYPE2;
}
template <char... Vs>
std::integral_constant<int, ival(Vs...)> operator""_i() {
    return {};
}
template <char... Vs>
std::integral_constant<ElementType, etval(Vs...)> operator""_et() {
    return {};
}

template<ElementType elementType, int size>
struct DataType
{
    DataType(std::integral_constant<ElementType, elementType>, std::integral_constant<int, size> ic):
        elementType_(elementType),
        size_(ic)
    {
    }
    ElementType elementType_;
    int size_;
};
int main()
{
    auto d1 = DataType(1_et, 1_i);
}

[live demo]