Извлечь параметры шаблона С++
Хотя я сомневаюсь, мне любопытно, можно ли извлекать параметры шаблона примитивного типа из существующего типа, возможно, используя RTTI.
Например:
typedef std::bitset<16> WordSet;
Можно ли извлечь номер 16 в указанном выше коде без жесткого кодирования в другом месте? Специальные реализации компилятора приветствуются, хотя меня особенно интересует g++
.
Ответы
Ответ 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