Генерация ошибок времени компиляции для недопустимых типов данных в классе шаблона?

Я использую C ++ для создания строкового класса. Я хочу, чтобы класс принимал только типы данных char и wchar_t, и я хочу, чтобы компилятор перехватывал любые недопустимые типы данных во время компиляции, используя #error. Я не люблю использовать assert (). Как я могу это сделать?

3.11.2009 01:04:56
Мне интересно, что делает другие типы недействительными?
GManNickG 3.11.2009 01:51:15
Обратите внимание, что #errorиспользуется при предварительной обработке, вы не можете использовать его во время компиляции - вот почему вам нужны упомянутые статические утверждения.
Georg Fritzsche 3.11.2009 02:29:54
2 ОТВЕТА

Вы можете использовать статическое утверждение. Повышение обеспечивает один .

Может быть что-то вроде:

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>

template <typename T>
class my_string
{
public:
    // ...
private:
    BOOST_STATIC_ASSERT((boost::is_same<T, char>::value ||
                          boost::is_same<T, wchar_t>::value));
};

int main(void)
{
    my_string<char> chstr;
    my_string<wchar_t> wstr;

    // fails
    my_string<int> istr;
}

Если вы не можете использовать Boost, вы можете легко переделать static-assert и is_same:

// static assert failure
template <bool Predicate>
struct STATIC_ASSERT_FAILURE;

template <>
struct STATIC_ASSERT_FAILURE<true> {}; // only true is defined

// static assert test
template <unsigned TestResult>
struct static_assert {};

// static assert macro
#define STATIC_ASSERT(x) typedef static_assert< \
                          sizeof(STATIC_ASSERT_FAILURE<(x)>)> \
                          _static_assert_test_

// value is true if T and U are the same type
template <typename T, typename U>
struct is_same
{
    static const bool value = false;
};

template <typename T>
struct is_same<T, T>
{
    static const bool value = true;
};

template <typename T>
class my_string
{
public:
    // ...
private:
    STATIC_ASSERT((is_same<T, char>::value || is_same<T, wchar_t>::value));
};

int main(void)
{
    my_string<char> chstr;
    my_string<wchar_t> wstr;

    // fails
    my_string<int> istr;
}

Обратите внимание, что если вы дважды используете статическое утверждение в одном и том же пространстве имен, вы получите конфликт имен. Вы должны использовать более сложную версию, которая использует макрос, например, __COUNTER__для генерации уникальных имен.

Вышеуказанное работает как в GCC 4.4, так и в Visual Studio 2008.

12
3.11.2009 03:05:58
На самом деле, я бы порекомендовал BOOST_MPL_ASSERT_MSG, поскольку выдаваемое компилятором сообщение становится более читабельным.
Matthieu M. 3.11.2009 08:44:08

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

template <class C> class limiter;

Затем специализируйте его для char и wchar_t и определите некоторое свойство.

template <>
class limiter<char>
{
public:
    typedef char limit_type;
}

template <>
class limiter<wchar_t>
{
public:
    typedef wchar_t limit_type;
}

В вашем строковом классе вы можете ссылаться на:

template <class TYPE>
class mystring
{
   typedef typename limiter<TYPE>::limit_type limit_type;
   ...
}

Поскольку это будет допустимо только для char и wchar_t, другие типы не будут создаваться.

5
3.11.2009 01:11:37
Спасибо! Вот какое еще решение я хотел! Я пытался использовать специализацию, прежде чем опубликовать, но не мог понять, как генерировать ошибки компилятора! Это мое решение: [code] template <typename T> struct string_type; шаблон <> struct string_type <char> {}; шаблон <> struct string_type <wchar_t> {}; шаблон <typename T> строка класса: string_type <T> {...};
Marlon 3.11.2009 01:24:33
Честно говоря, это конкретная реализация статического утверждения. Вы должны предпочесть использовать более общее решение.
GManNickG 3.11.2009 01:47:25
@GMan, иногда общее решение труднее понять, чем конкретное. Но ваше решение лучше, конечно, в общем случае.
Kirill V. Lyadvinsky 3.11.2009 05:44:20