在编译时确保模板类型的一致性

时间:2011-01-24 16:20:49

标签: c++ templates typedef

我有这个模板类:

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:
    ...
}

我想确保TinTout都是typedef类型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;

即使使用相同类型的检查(在从未实际调用但会导致编译器错误的静态函数中创建不兼容的指针赋值),我也不会遇到编译器错误。

有没有办法创建静态编译时类型一致性检查?为什么我使用的那个不工作?

注意:暂时忽略一下摆脱模板参数的明显解决方案。这将“解决”这个问题,但是我的调试工具正在进行一些带外事情,其中​​typedef用于传递重要的元数据:我想确保Foo.input的类型为{{ 1}}其中TinTin或typedef,可解析为int16_t,类似于int16_tFoo.output。从我的调试工具的角度来看,略有不同,其中可以区分typedef类型及其基类型,即使在C ++程序中它们是相同的。


编辑:顺便说一下,这是一个嵌入式系统,我不能使用Boost。它也不是C ++ 0x。

6 个答案:

答案 0 :(得分:5)

您可以在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");

您也可以在Boost中找到the is_same type traitstatic assert。即使您正在为嵌入式系统进行编译,也可以直接从Boost中提取类型特征和静态断言头,并且这些库都没有任何运行时开销。

答案 1 :(得分:4)

一个简单的方法:

template <class, class> class Foo;

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

另一方面,如果你的条件实际上更复杂,那就是使用来自Boost的BOOST_STATIC_ASSERT或来自C ++ 0x的static_assert。既然你想要非Boost选项并且C ++ 0x可能不起作用,这里的内容更类似于你在例子中发布的内容:

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

Tout相同。这需要在某个方法中被调用或者具有其地址(这样做的惯用语是在the Boost.Concept_check implementation documentation的末尾)。如果您想要其他人发布的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 :(得分:2)

虽然你不能使用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;
// ...
};

答案 3 :(得分:2)

您的方法有效,但您必须在某处调用__ensure_type_consistency()以便编译器抛出错误。如果从未调用该方法,则编译器认为它可以忽略它。

我刚刚在VC ++ 2010中尝试过它,它可以工作。


你在使用GCC吗?尝试在__ensure_type_consistency上使用属性((used))。

答案 4 :(得分:0)

您可以使用Boost Concept Checks:

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

答案 5 :(得分:0)

我已经针对这个问题调整了几个回答,这似乎很好地解决了这个问题:

辅助类:

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();
    }
    ...
}