Нетипичные параметры шаблона, конструктор и руководство по выводам - PullRequest
0 голосов
/ 27 февраля 2019

Я хочу иметь шаблон структуры, который определяется конкретными значениями его компонентов, передаваемых ему во время конструирования, чтобы различные значения создавали разные типы данных 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]

Обратите внимание, что я не могу использовать аргументы шаблона типа, так как два типа аргументов являются фиксированными (ElementType и int), но DataType(ElementType::TYPE1, 1) должны быть разнымитип чем DataType(ElementType::TYPE1, 2) и DataType(ElementType::TYPE1, 1) должен отличаться от DataType(ElementType::TYPE2, 1).

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Чтобы использовать дедукцию, значение, которое вы передаете конструктору, должно быть константным выражением.К сожалению, значения, передаваемые в качестве параметра, теряют свои свойства 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]

Чтобы сделать его более удобным, вы можете обернуть целочисленное const с помощью суффиксных операторов constexpr:

#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]

0 голосов
/ 27 февраля 2019

Вы можете определить свой шаблон следующим образом:

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

И создать его экземпляр следующим образом:

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

Демо

...