2014-10-03 2 views
4

Этот вопрос в духе последующий дальше от этого вопроса от другого пользователя, который имеет отличные ответы: Is it possible to write a template to check for a function's existence?Можно ли написать шаблон C++ для проверки существования конструктора?

Я хочу делать то, что описано в этом вопросе, за исключением того, я хочу, чтобы быть в состоянии сделать это для конструктора. Например, учитывая эти два типа:

class NormalType 
{ 
public: 
    NormalType() 
    { 
     std::cout << "NormalType::NormalType()" << std::endl; 
    } 
}; 

class SpecialType 
{ 
public: 
    SpecialType() 
    { 
     std::cout << "SpecialType::SpecialType()" << std::endl; 
    } 
    SpecialType(int someArg) 
    { 
     std::cout << "SpecialType::SpecialType(int someArg)" << std::endl; 
    } 
}; 

И это вспомогательная функция для построения объекта:

template<class T> 
class ConstructHelper 
{ 
public: 
    template<bool HasSpecialConstructor> 
    static T Construct() 
    { 
     return T(); 
    } 
    template<> 
    static T Construct<true>() 
    { 
     return T(int(42)); 
    } 
}; 

Я хочу, чтобы иметь возможность писать код так:

NormalType normalType = ConstructHelper<NormalType>::Construct<has_special_constructor<NormalType>::value>(); 
SpecialType specialType = ConstructHelper<SpecialType>::Construct<has_special_constructor<SpecialType>::value>(); 

где желаемые результаты заключаются в том, что вызывается NormalType::NormalType(), и вызывается . Недостающим компонентом здесь является тот критический has_special_constructor помощник, который может определить, существует ли наш специальный конструктор для данного типа.

В предыдущем вопросе я ссылался на сделки с проверкой, существует ли данная функция для типа, и было представлено множество рабочих решений. К сожалению, большинство из них полагаются на возможность использовать адрес целевого метода, и в соответствии с спецификацией C++ вы не можете взять адрес конструктора (12.1.10). Из оставшихся рабочих решений все они, как представляется, полагаются на SFINAE с decltype на произвольное выражение в шаблонной специализации. Это простой способ решить эту проблему, но, к сожалению, я работаю над Visual Studio 2013, которая не поддерживает правила SFINAE C++ 11 и до сих пор не будет выпускать «Visual Studio 14» либо , При правильной поддержке SFINAE, я должен быть в состоянии сделать это, например:

template<class T> 
struct has_special_constructor 
{ 
    template<class S> 
    struct calculate_value: std::false_type {}; 
    template<> 
    struct calculate_value<decltype(T(int(42)))>: std::true_type {}; 

    static const bool value = calculate_value<T>::value; 
}; 

Но это не компилируется под VS2013, если я пытаюсь проверить тип, который не определяет мой целевой конструктор, из-за отсутствия поддержки SFINAE. Тем не менее, я еще не уверен, что это невозможно, я думаю, что может быть способ заставить его работать, но пока я не смог найти решение. Кто-нибудь есть способ сделать это, что я упустил?

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

  • Это должно быть возможным разрешить has_special_constructor<T>::value для любого заданного типа без дополнительного кода записывается для этого конкретного типа.

  • Я в первую очередь ориентирован на Visual Studio 2013, поэтому любое решение должно работать в этой среде. Я знаю, что полностью соответствующий C++ 11 компилятор может справиться с этой проблемой более легко, но я ищу что-то, что может теперь функционировать в текущем целевом компиляторе.

  • Если кто-нибудь может предоставить решение, которое работает в компиляторе C++ 03 (IE, без каких-либо возможностей C++ 11), я соглашусь с тем, что использует возможности C++ 11.

  • В этот момент я бы согласился на временное обходное решение на основе расширения MSVC, так как я могу использовать препроцессор, чтобы вернуться к этому методу, пока не появится полная поддержка C++ 11.

ответ

7
template<class T> 
using has_special_constructor = std::is_constructible<T, int>; 

Возможные "C++ 03" версия:

template <class T> 
struct has_special_constructor { 
    typedef char one; 
    typedef struct { char _[2];} two; 

    template <std::size_t> 
    struct dummy {}; 

    template<class U> 
    static one f(dummy<sizeof(U(42))>*); 
    template<class> 
    static two f(...); 

    static const bool value = sizeof(f<T>(0)) == sizeof(one); 
}; 

Это работает на г ++ 4.4 или более поздней версии в режиме C++ 03. Я полагаю, что «C++ 03» находится в страшных котировках, поскольку это зависит от выражения SFINAE, которое seems to be a bit of a gray area in C++03 - по-видимому, формулировка C++ 03 позволила это сделать, но ни один крупный поставщик компилятора фактически не поддерживал его, пока C++ 11 почти не находится здесь (GCC 4.4 был выпущен в 2009 году), поэтому можно утверждать, позволяет ли «чистый» C++ 03 ...

+0

Hah! Просто как тот! Мне нужно снова пройти список черт типа C++ 11 и передать их в память, я думаю. Я просто потратил 3 часа на поиск решения этой проблемы. –

+0

За бонусные баллы * (ну, не совсем, но я бы, если бы мог!) Любая идея, если std :: is_constructible может быть эмулирован в компиляторе C++ 03? –

+0

@RogerSanders См. Мое редактирование. Я считаю, что для этого вам нужно выражение SFINAE, которое является * видом * C++ 03, я думаю. –

Смежные вопросы