2009-06-04 3 views
7

Есть ли способ проверить во время компиляции, если какой-либо класс имеет конструктор с определенными аргументами? ?Проверка на подпись конструктора времени компиляции

Например:

class foo { 
    foo(std::string &s) { 
    } 
}; 

Я хочу, чтобы проверить во время компиляции, что конструктор с станд :: строка & всегда определена. Может быть, boost обеспечивает такую ​​функциональность?

+0

Вы имеете в виду, не пытаясь создать объекты? – Naveen

+1

Если вы используете этот конструктор, пока он не определен, компилятор будет генерировать ошибку. Если вы не используете его, то почему вы хотите, чтобы он присутствовал? –

+0

Интересный тестовый файл для любой предлагаемой проверки - std :: string. – MSalters

ответ

3

Если вам действительно нужно, вы можете добавить эту функцию:

static void _dummy() { std::string s; foo f(s); } 

Без вашего конструктора, компиляция потерпит неудачу. Примечание: ваш конструктор является закрытым. Если это специально, то в классе должен находиться _dummy. В противном случае вы можете получить его вне класса.

Кроме того, вы можете templatize или даже сделать его макросом, если это очень часто происходит в вашем коде.

Но, честно говоря, он по-прежнему выглядит как взломанный. Вы уверены, что вам это нужно?

0

То, о чем вы просите, звучит очень похоже на единичный тест. Я бы загрузил что-то вроде cppunit и интегрировал его в вашу компиляцию.

Все юнит-тесты, которые вы пишете, будут построены/выполнены во время компиляции. См. Unit Testing для получения дополнительной информации.

+0

Модульные тесты на самом деле не во время компиляции, и это было очень четко задано. Уже есть 2 решения, которые доказывают, что это вполне возможно. – MSalters

+0

Тесты модулей не являются проверкой времени компиляции, но они могут быть настроены для запуска при компиляции кода. Это дает вам то, что вы, вероятно, ищете в любом случае, что является способом проверки функциональных контрактов и предположений о вашем коде. Есть ли причина, почему это должно произойти во время компиляции? –

0

Если вам нужен этот вид проверки, вам, вероятно, потребуется некоторое другое время компиляции проверки

я предлагаю взглянуть повысить проверки библиотеки концепции (документация here). Вы можете найти документацию, классы и макросы, которые могут вам помочь.

3

Если вы пытаетесь проверить, является ли foo конструктивным из строки, вы можете использовать boost::is_convertible.

Например:

BOOST_STATIC_ASSERT((boost::is_convertible<std::string, foo>::value)); 
2

Использование проверки Концепция в наддува 1.39:

#include <boost/concept_check.hpp> 

class foo_c 
{ 
public: 
    foo_c(std::string& s) 
    {} 
}; 

template<typename T> 
class algo_c 
{ 
BOOST_CONCEPT_ASSERT((boost::Convertible<std::string,T>)); 
public: 
    algo_c() 
    {} 
}; 

Удаление или изменение конструктора foo_c результата в следующей компиляции ошибки времени:

error C2440: 'initializing' : cannot convert from 'std::string' to 'foo_c'

EDIT: Это может быть сделано для работы с явным конструктором с homem ADE проверка концепции:

template <typename T> 
struct HasTheRightConstructor 
{ 
    BOOST_CONCEPT_USAGE(HasTheRightConstructor) 
    { 
     std::string v; 
     T j(v); 
    } 
}; 
+1

Этот метод не работает для явных конструкторов. Он работает только для конструкторов с 1 аргументом не по умолчанию. Он не работает, если оператор преобразования определен из «std :: string» в T –

+0

Хорошая точка. Отредактировано так, что оно работает с явным ctor. Не знаю, как это сделать, чтобы соответствовать точному прототипу (не могу ответить от MSalters на компиляцию – 2009-06-04 14:21:48

6

Распространенный способ проверить, является ли конкретная функция существует, чтобы взять его адрес и назначить его фиктивной переменной. Это намного точнее, чем упомянутые выше тесты, поскольку это проверяет точную сигнатуру функции. И вопрос был конкретно о string& в сигнатуре, поэтому неконстантный и, следовательно, предположительно изменяющий строку.

Однако в этом случае вы не можете использовать трюк take-the-address-and-assign-it: у конструкторов нет адресов. Итак, как вы проверяете подпись? Просто: Подружитесь с ним в фиктивном классе.

template<typename T> 
class checkSignature_StringRef { 
    friend T::T(string&); 
}; 

Это тоже очень специфическая проверка: она даже не будет соответствовать другим подобным конструкторам как foo::foo(std::string &s, int dummy = 0).

+0

Это не скомпилировано с VC8: класс содержит явное переопределение «T :: {ctor}», но не происходит из интерфейса который содержит объявление функции – 2009-06-04 14:08:23

+0

Обратите внимание на отчет о дефекте здесь: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#215 –

+0

crash on gcc3! Ошибка компиляции на gcc4 ... Это метод выглядит неплохо, но я был бы рад узнать, что кто-то еще его скомпилировал ... – 2009-06-04 15:09:00

1

Я столкнулся с аналогичной проблемой, желающей переслать конструкторы в базовый класс, когда аргументы совместимы, и сделать что-то еще, когда нет.

Вот обобщенные черты работают на MSVC 2013 (требуется C++ 11 материала):

namespace detail { 
    template<class type,class...Args> 
    class constructible_from 
    { 
     template<class C> 
     static C arg(); 

     template <typename U> 
     static boost::mpl::true_ constructible_test(U *, decltype(U(arg<Args>()...)) * = 0); 
     static boost::mpl::false_ constructible_test(...); 

    public: 

     typedef decltype(constructible_test(static_cast<type*>(nullptr))) result; 

    }; 
} // namespace detail 

template<class type> 
struct constructible 
{ 
    template<class...Args> 
    struct from : 
     detail::constructible_from<type,Args...>::result {}; 
}; 

Вот пример использования черт, я оставляю enable_if применения в качестве упражнения: D:

struct b{}; 
struct c{}; 
struct d : c{}; 

struct a 
{ 
    a() {} 
    a(a &) {} 
    a(b,c) {} 
    a(c) {} 
}; 


static_assert(
    constructible<a>::from<>::value, 
    "a()" 
); 
static_assert(
    constructible<a>::from<a&>::value, 
    "a(a&)" 
); 
static_assert(
    ! constructible<a>::from<const a&>::value, 
    "a(const a&)" 
); 
static_assert(
    constructible<a>::from<b,c>::value, 
    "a(b,c)" 
); 
static_assert(
    ! constructible<a>::from<b>::value, 
    "a(b)" 
); 
static_assert(
    constructible<a>::from<c>::value, 
    "a(c)" 
); 
static_assert(
    constructible<a>::from<d>::value, 
    "a(d)" 
); 
Смежные вопросы