#c #templates #types
#c #шаблоны #типы
Вопрос:
Я пытался ответить на вопрос в названии, но я в тупике. В основном, пытаюсь выяснить, есть ли встроенный способ указать «источник» экземпляра шаблона, по крайней мере, для классов. Вот пример того, что я хотел бы сделать:
template<class T>
class A { };
auto a = A<int>();
template<class T>
auto someFunction(T item) {
if(/* if type of a is from the templated class A */) {
// yep A<int> is 'from' A.
}
}
Возможно ли это каким-либо способом, подобным этому? Я мог бы использовать некоторые сохраненные значения или махинации с наследованием, чтобы получить что-то подобное, но я бы предпочел этого не делать.
Комментарии:
1. просто
A<T>
, или любойC<Ts...>
, или такжеstd::array<T, N>
?2. Вы хотите определить
struct Der : A<int> {}
?3. @Jarod42 просто любые
A<T>
s, но ничего больше. Итак, исключая ваши следующие два примера.
Ответ №1:
Возможно, с помощью пользовательских свойств типа.
Что-то вроде следующего
template <typename>
struct is_A : public std::false_type
{ };
template <typename T>
struct is_A<A<T>> : public std::true_type
{ };
// ...
template <typename T>
auto someFunction(T item) {
if( is_A<T>::value ) {
// yep A<int> is 'from' A.
}
}
Или, может быть, вы хотите перехватывать не только A<T>
, но, в общем, все типы, являющиеся шаблонным типом, возможно, с неопределенным количеством аргументов шаблона?
В этом случае вы можете попробовать что-то вроде следующего
template <typename>
struct is_template : public std::false_type
{ };
template <template <typename...> class C, typename ... Ts>
struct is_template<C<Ts...>> : public std::true_type
{ };
Проблема: этот тип traits перехватывает все типы шаблонов с аргументами шаблона types и только аргументы шаблона. Но не перехватывает, например, std::integer_sequence<int, 0, 1, 2, 3, 4, 5>
которые получают тип и некоторый параметр шаблона, не относящийся к типу.
Вы можете добавить другие специализации для is_template
, чтобы перехватить другие случаи, но вы не можете определить специализацию, которая улавливает все типы шаблонов (все комбинации параметров шаблона).
Комментарии:
1. Обратите внимание, что это нарушает LSP; сделайте
A
окончательным, если вы это сделаете.2. @Yakk-AdamNevraumont — эммм … извините, я не понимаю, что вы имеете в виду.
3. Ах. en.wikipedia.org/wiki/Liskov_substitution_principle — что производный тип может быть заменен на его родительский. Если
A<int>
не является окончательным, а B является производным отA<int>
, ваш код при передаче будет вести себя иначе,A<int>
чемB
. Следовательно, нарушает LSP.4. @max66 Я считаю, что это нарушение подстановки LSP можно было бы устранить, если бы шаблон использовался
std::condition
для определения, унаследован ли он отtrue_type
илиfalse_type
, вместо использования специализации.
Ответ №2:
Используйте признак типа
#include <type_traits>
#include <iostream>
template<class T>
class A { };
auto a = A<int>();
template <typename X>
struct is_from_A : std::false_type {};
template <typename T>
struct is_from_A<A<T>> : std::true_type {};
int main() {
std::cout << is_from_A<int>::value << "n"; // 0
std::cout << is_from_A<A<int>>::value << "n"; // 1
}
Комментарии:
1. Прекрасно! Спасибо. Как называется синтаксис в строке
struct is_from_A<A<T>> : ...
? Я думал, что специализации шаблонов могут использовать только явные значения, т.Е.is_from_A<A<int>> : ...
, но, по-видимому, это не так.2. @AnthonyMonterrosa: И поэтому это частичная специализация (кстати, недоступная для функции).
Ответ №3:
Другой способ, позволяющий производному классу соответствовать:
template <typename T>
std::true_type is_an_A_impl(A<T>*);
std::false_type is_an_A_impl(...);
template <typename T>
using is_a_A = decltype(is_an_A_impl(std::declval<T*>()));