Если мы попросим компилятор рассказать нам что-нибудь о классе класса T
, который не был объявлен , мы обязаны получить ошибку компиляции. Нет пути вокруг этого. Поэтому, если мы хотим знать, существует ли класс T
, где T
еще не объявлен, мы должны сначала объявить T
.
Но это нормально, потому что просто объявляя T
не будет делать это «есть», так как то, что мы должны в виду под T
существует является T
определяется. И если, объявив T
, , вы можете определить, есть ли уже , вам не обязательно быть в любой путаницы.
Таким образом, проблема заключается в определении того, является ли T определенным типом класса.
sizeof(T)
здесь не поможет. Если T
не определено, это даст ошибку incomplete type T
. Аналогично typeid(T)
. Не является ли хорошо обрабатывая тестовое SFINAE о типе T *
, потому что T *
является представляет собой определенный тип до тех пор, как T
было объявлено, даже если T
нет. А так как мы обязаны декларировать класс T
, std::is_class<T>
- это не ответ , потому что для этого объявления достаточно сказать «Да».
C++ 11 предоставляет std::is_constructible<T ...Args>
в <type_traits>
.Может это предложение без проблем? - учитывая, что если определено T
, то оно должно содержать , по меньшей мере, один конструктор.
Я не боюсь. Если вы знаете подпись хотя бы одного публичного конструктора T
, то <type_traits>
(по состоянию на 4.6.3) GCC действительно будет заниматься бизнесом . Скажем, что один известный публичный конструктор - T::T(int)
. Тогда:
std::is_constructible<T,int>::value
будет справедливо, если T
определено и ложно, если T
просто декларируется.
Но это не переносится. <type_traits>
в VC++ 2010 еще не обеспечивает std::is_constructible
и даже его std::has_trivial_constructor<T>
будет блевать, если T
не определен: скорее всего, когда std::is_constructible
действительно прибудет будет следовать этому примеру. Кроме того, в случае, если существуют только частные конструкторы T
, то для предложения std::is_constructible
тогда даже GCC будет barf (который поднимает брови).
Если определено T
, оно должно иметь деструктор и только один деструктор. И что деструктор, вероятно, будет публичным, чем любой другой возможный член T
. В этот свет, простейшая и самая сильная игра, которую мы можем сделать, состоит в создании зонда SFINAE на предмет наличия T::~T
.
Этого SFINAE зонд не может быть сделан в обычном способе для определения того, имеет ли T
обычной функции члена mf
- делая «Да перегрузки» функции зонда SFINAE принимать аргумент, который определен в терминах из в тип &T::mf
. Потому что нам не разрешено указывать адрес деструктора (или конструктора) .
Тем не менее, если T
определено, то T::~T
имеет тип DT
- который должен быть , выданное посредством decltype(dt)
всякий раз, когда dt
это выражение, которое вычисляется в вызове T::~T
; и поэтому DT *
будет также типом, который может использоваться в качестве аргумента функции перегрузки функции в принципе . Поэтому мы можем написать зонд, как это (GCC 4.6.3):
#ifndef HAS_DESTRUCTOR_H
#define HAS_DESTRUCTOR_H
#include <type_traits>
/*! The template `has_destructor<T>` exports a
boolean constant `value that is true iff `T` has
a public destructor.
N.B. A compile error will occur if T has non-public destructor.
*/
template< typename T>
struct has_destructor
{
/* Has destructor :) */
template <typename A>
static std::true_type test(decltype(std::declval<A>().~A()) *) {
return std::true_type();
}
/* Has no destructor :(*/
template<typename A>
static std::false_type test(...) {
return std::false_type();
}
/* This will be either `std::true_type` or `std::false_type` */
typedef decltype(test<T>(0)) type;
static const bool value = type::value; /* Which is it? */
};
#endif // EOF
только с тем ограничением, что T
должны общественных деструктора будет юридически использован в выражении аргумента decltype(std::declval<A>().~A())
. (has_destructor<T>
является упрощенной адаптацией метода-интроспекцией шаблона я способствовал here.)
Смысл этого аргумента выражение std::declval<A>().~A()
может быть неясным для некоторых, в частности, std::declval<A>()
.Шаблон функции std::declval<T>()
определяется в <type_traits>
и возвращает T&&
(RValue ссылку на T
) - хотя оно может быть использовано только в невычисленном контекстов, такие как аргумент decltype
. Таким образом, значение std::declval<A>().~A()
- a ~A()
с некоторыми данными A
. std::declval<A>()
служит нам здесь, устраняя необходимость в том, чтобы там был любой общественный конструктор T
, или для нас, чтобы узнать об этом.
Соответственно, аргумент типа зонда SFINAE для «Да перегрузок» является: указателя типа деструктора A
и test<T>(0)
будет соответствовать перегрузки только в случае, если есть такой тип в качестве деструктора A
, для A
= T
с has_destructor<T>
в руке - и ее ограничение публично разрушаемые значения T
твердо в виду - вы можете проверить, является ли класс T
определенный на некоторый момент в вашем коде, гарантировав, что вы объявите перед тем, как задать вопрос . Вот тестовая программа.
#include "has_destructor.h"
#include <iostream>
class bar {}; // Defined
template<
class CharT,
class Traits
> class basic_iostream; //Defined
template<typename T>
struct vector; //Undefined
class foo; // Undefined
int main()
{
std::cout << has_destructor<bar>::value << std::endl;
std::cout << has_destructor<std::basic_iostream<char>>::value
<< std::endl;
std::cout << has_destructor<foo>::value << std::endl;
std::cout << has_destructor<vector<int>>::value << std::endl;
std::cout << has_destructor<int>::value << std::endl;
std::count << std::has_trivial_destructor<int>::value << std::endl;
return 0;
}
Построенный с GCC 4.6.3, это скажет вам, что 2 // Defined
классы имеют деструкторов и 2 // Undefined
классы не делают. В пятой строке вывода будет указано, что int
является разрушаемым, а окончательная строка покажет, что соглашается std::has_trivial_destructor<int>
. Если мы хотим, чтобы сузил поле к типам классов, std::is_class<T>
может быть применено после , мы определяем, что T
является разрушаемым.
Visual C++ 2010 не предоставляет std::declval()
. Чтобы поддержать этот компилятор вы можете добавить следующую строку в верхней части has_destructor.h
:
#ifdef _MSC_VER
namespace std {
template <typename T>
typename add_rvalue_reference<T>::type declval();
}
#endif
Вы хотите определить, содержит ли класс тип ar? Или, если тип существует в области пространства имен? (Я не вижу, как последнее будет полезно). – sbabbi
Компилятор сделает это за вас. Пожалуйста, объясните, что вы хотите сделать? –
Чтобы уточнить - класс является просто жестко запрограммированным идентификатором, поэтому он не зависит от замены параметров шаблона вообще? – ndkrempel