Обеспечение согласованности типов шаблонов во время компиляции - PullRequest
3 голосов
/ 24 января 2011

У меня есть шаблон этого класса:

template <class Tin, class Tout>
class Foo
{
    Tin input;
    Tout output;

    static inline void __ensure_type_consistency
    {
        int16_t* p = (int16_t *)0;
        // uint16_t* p1 = p;
        Tin* check_type_in = p;
        Tout* check_type_out = p;  
    }
public:
    ...
}

Я хочу убедиться, что Tin и Tout оба typedef'd для типа int16_t, а не какой-то другой тип.( ПРИМЕЧАНИЕ: . Пожалуйста, прочитайте полный вопрос, прежде чем делать выводы )

Если я раскомментирую закомментированную строку, я получаю ожидаемую ошибку;компилятор не позволяет указателям разных типов присваиваться друг другу без приведения:

"src\foo.h", line 47: error #145: a value of type "int16_t *" 
cannot be used to initialize an entity of type "uint16_t *"

Но если я оставлю это закомментированным, и я создаю его экземпляр:

Foo<uint16_t, int32_t> illegalFoo;

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

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

NOTE : на мгновение игнорировать очевидное решениепросто избавиться от параметров шаблона.Это "решило бы" эту проблему, но здесь есть некоторые внеполосные вещи, происходящие здесь с моими инструментами отладки, где используются typedef для передачи важных метаданных: я хочу убедиться, что Foo.input имеет тип Tin, гдеTin - это либо int16_t, либо typedef, который разрешается как int16_t, так же как с Foo.output и Tout.Существуют небольшие различия с точки зрения моих инструментов отладки, где можно различать типы typedef и их базовый тип, даже если в программе на C ++ они идентичны.


edit: кстати, это встроенная система, и я не могу использовать Boost.Это также не C ++ 0x.

Ответы [ 6 ]

5 голосов
/ 24 января 2011

Вы можете использовать черту типа is_same в static_assert.C ++ 0x будет выглядеть так:

static_assert(std::is_same<Tin, std::int16_t>::value &&
              std::is_same<Tout, std::int16_t>::value, "o noez");

Вы также можете найти как is_same type trait , так и static assert в Boost.Даже если вы компилируете для встроенной системы, просто извлечь из Boost только черты типа и статические заголовки утверждений, и ни одна из этих библиотек не будет иметь никаких накладных расходов во время выполнения.

4 голосов
/ 24 января 2011

Один простой способ:

template <class, class> class Foo;

template <>
class Foo<int16_t, int16_t> {
  ...
};

Другой способ, если ваши условия на самом деле более сложные, - это использовать BOOST_STATIC_ASSERT из Boost или static_assert из C ++ 0x. Поскольку вы хотели, чтобы параметры не-Boost и C ++ 0x могли не работать, вот что-то более похожее на то, что вы опубликовали в своем примере:

(void)(true ? (int16_t**)0 : (Tin**)0);

и то же самое для Tout. Это должно быть в каком-то методе, который либо вызывается, либо его адрес берется (идиома для этого находится в конце документации по реализации Boost.Concept_check ). Если вы хотите что-то вроде решения is_same / static_assert, опубликованного другими, но без Boost или C ++ 0x, попробуйте:

template <class, class> struct types_valid {static const int value = -1;};
template <> struct types_valid<int16_t, int16_t> {static const int value = 1;};

Затем поместите static char foo[types_valid<Tin, Tout>::value]; в свой класс вне каких-либо методов. Я полагаю, что вам не нужно будет определять foo, если вы нигде не ссылаетесь на него.

2 голосов
/ 24 января 2011

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

Я только что попробовал это в VC ++ 2010, и он работает.


Вы используете GCC? Попробуйте использовать атрибут ((используется)) в __ensure_type_consistency.

2 голосов
/ 24 января 2011

Хотя вы не можете использовать boost или C ++ 1x, вы можете создать свой собственный is_same компаратор типа времени компиляции и взломать утверждение какого-то бедного человека во время компиляции

// Beware, brain-compiled code ahead!
template< typename T1, typename T2>
struct is_same      { static const bool result = false; };

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

template< bool Condition, typename Dummy = void >
struct static_assert {
  typedef bool result;
};

template<typename IntentionalError>
struct static_assert<false,IntentionalError> {
  typedef typename IntentionalError::does_not_exist result;
};

и используйте его так:

template <class Tin, class Tout>
class Foo
{
    Tin input;
    Tout output;

    typedef typename static_assert<is_same<Tin ,int16_t>::result>::result Tin_test;
    typedef typename static_assert<is_same<Tout,int16_t>::result>::result Tout_test;
    typedef typename static_assert<is_same<Tout,Tout   >::result>::result Tout_test;
// ...
};
0 голосов
/ 24 января 2011

Я адаптировал несколько ответов на этот вопрос, и это, кажется, хорошо помогает:

Класс помощника:

template <typename T1, typename T2>
struct TypeConsistency
{
private:
    static inline void checkfunction()
    {
        T1* p1 = (T1 *)0;
        T2* p2 = p1;
    }
public:
    static inline void check() { checkfunction; }
    /* The above line does nothing at runtime,
     * but takes the address of checkfunction(),
     * which causes a compile-time type check.
     */ 
};

Применение этого в моем классе foo:

template <class Tin, class Tout> 
class Foo
{
    Tin input;
    Tout output;

public:
    Foo() { 
        TypeConsistency<int16_t, Tin>::check();
        TypeConsistency<int16_t, Tout>::check();
    }
    ...
}
0 голосов
/ 24 января 2011

Вы можете использовать концептуальные проверки повышения:

BOOST_CONCEPT_ASSERT((boost::Integer<Tin>));
BOOST_CONCEPT_ASSERT((boost::Integer<Tout>));

См. http://www.boost.org/doc/libs/1_45_0/libs/concept_check/using_concept_check.htm

...