Проверьте во время компиляции подпись конструктора класса - PullRequest
8 голосов
/ 04 июня 2009

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

Например:

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

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

Ответы [ 7 ]

7 голосов
/ 04 июня 2009

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

Однако, в этом случае вы не можете использовать трюк «взять адрес и назначить»: у конструкторов нет адресов. Так как же тогда проверить подпись? Просто: подружитесь с ним на манекене.

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

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

3 голосов
/ 04 июня 2009

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

Например:

BOOST_STATIC_ASSERT((boost::is_convertible<std::string, foo>::value));
3 голосов
/ 04 июня 2009

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

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

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

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

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

2 голосов
/ 05 февраля 2015

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

Вот обобщенные черты, работающие на 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)"
);
2 голосов
/ 04 июня 2009

Использование проверки концепции в надстройке 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 приводит к следующей ошибке времени компиляции:

ошибка C2440: «инициализация»: невозможно преобразовать из 'std :: string' в 'foo_c'

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

template <typename T>
struct HasTheRightConstructor
{
    BOOST_CONCEPT_USAGE(HasTheRightConstructor)
    {
        std::string v;
        T j(v);
    }
};
0 голосов
/ 04 июня 2009

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

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

0 голосов
/ 04 июня 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...