Подтвердить что ты не робот

Извлечь параметры шаблона С++

Хотя я сомневаюсь, мне любопытно, можно ли извлекать параметры шаблона примитивного типа из существующего типа, возможно, используя RTTI.

Например:

typedef std::bitset<16> WordSet;

Можно ли извлечь номер 16 в указанном выше коде без жесткого кодирования в другом месте? Специальные реализации компилятора приветствуются, хотя меня особенно интересует g++.

4b9b3361

Ответ 1

Это невозможно. Обычно вы делаете это:

template<int N>
struct foo {
    static const int value = N;
};

и для типов

template<typename T>
struct foo {
    typedef T type;
};

Вы можете получить к нему доступ, а затем foo<39>::value или foo<int>::type.

Если у вас есть определенный тип, вы можете использовать частичную специализацию по шаблону:

template<typename>
struct steal_it;

template<std::size_t N>
struct steal_it< std::bitset<N> > {
    static const std::size_t value = N;
};

Такой же принцип возможен и для параметров типа. Теперь вы можете передать любой битсет, например steal_it< std::bitset<16> >::value (обратите внимание, чтобы использовать size_t, а не int!). Поскольку у нас еще нет переменных параметров шаблона, мы должны ограничить себя определенным количеством параметров и повторить специализированные шаблоны steal_it для подсчета от 1 до N. Другой трудностью является сканирование типов, которые имеют смешанные параметры (типы и не- типы). Это, вероятно, нетривиально для решения.

Если у вас нет типа, но только его объект, вы можете использовать трюк, чтобы получить значение во время компиляции:

template<typename T>
char (& getN(T const &) )[steal_it<T>::value];  

int main() {
    std::bitset<16> b;
    sizeof getN(b); // assuming you don't know the type, you can use the object
}

Трюк заключается в том, чтобы заставить шаблон функции автоматически выводить тип, а затем возвращать ссылку на массив символов. Функция не нуждается в определении, единственное, что нужно, это ее тип.

Ответ 2

Вы можете легко сделать это в С++ 11, используя вывод аргументов и неоцененные контексты (обратите внимание, что для удобства демонстрация использует функцию шаблонов переменных С++ 14).

#include <type_traits>
#include <iostream>

template<int>
struct foo {};

template<int arg_N>
struct val {
    static constexpr auto N = arg_N;
};

template<template <int> typename T, int N>
constexpr auto extract(const T<N>&) -> val<N>;

template<typename T>
constexpr auto extract_N = decltype(extract(std::declval<T>()))::N;


int main() {
    std::cout << extract_N<foo<5>>;
}

Live demo

Ответ 3

В случае std::bitset вы можете просто использовать функцию члена size():

size_t sz = oh_my_word.size();  // sz is now 16

В общем случае вы можете определить функцию-член, которая возвращает размер аналогичным образом:

template <int N>
class Foo
{
public:
  int size() const { return N; }
};

Ответ 4

Как указано в других ответах, для std::bitset вы можете получить размер, используя функцию-член size(), которая должна быть правильным выбором, лучше, чем любой другой прием.

Было несколько предложений для общего случая, почти аналогичных тому, который я предлагаю ниже, но все же я думаю, что это проще:

template <template<std::size_t> typename T, std::size_t K>
auto extractSize(const T<K>&) {
    return K;
}

int main() {
    std::bitset<6> f1;
    std::bitset<13> f2;
    std::cout << extractSize(f1) << std::endl;
    std::cout << extractSize(f2) << std::endl;
}

Ответ 5

Мне нравится ответ марка Гарсии, потому что он показывает, как извлечь параметр шаблона универсальным способом, но я считаю, что его пример может быть проще:

#include <type_traits>
#include <iostream>

template<int>
struct MyType {};

template<template <int> typename T, int N>
constexpr int extract(const T<N>&) { return N; }

int main() {
    constexpr MyType<5> myObj;
    std::cout << extract(myObj);
}

Live demo