C ++ 14

时间:2017-01-08 22:56:55

标签: c++ c++11 c++14

我想在C ++ 14中为模板映射做一个模板。先验,似乎以下代码可以解决这个问题

template<class T>
struct KeyType {};

template<class T>
struct ValueType {
    T x;
};

template<template<class> class K>
struct Map;

template<>
struct Map<KeyType> {
    template<class T>
    using type = ValueType<T>;
};

ValueType<int> test{42};
Map<KeyType>::type<int> testM{42}; // Same as above

但是,使用 clang ++ v3.8 编译时,以下表达式将返回false。

template<template<class> class TemplateType>
struct NeedsTemplate;

std::is_same<
    NeedsTemplate<ValueType>,
    NeedsTemplate<Map<KeyType>::type>
>::value; // False

我明白为什么它是假的:it has already been answered here。基本上,该标准确保别名的模板实例化应该被识别为相同,但对模板本身没有任何说明。因此,使用 g ++ std::is_same为真,而使用 clang ++ ,则为false。

我的问题是:如何使用g ++和clang ++实现模板映射,以满足std::is_same要求?我愿意使用宏作为最后的手段...

2 个答案:

答案 0 :(得分:1)

一般来说,你所要求的等同于功能比较,它等同于暂停问题,即不可计算。然而...

如果您只想对某些特定的预定义模板执行此操作,则可以将它们专门用于标记类,然后可以在标记类上使用NeedsTemplate。也就是说,

namespace Reflect {
    struct Reflect {};
}

template<class T>
struct KeyType {};

namespace Reflect {
    struct KeyType {};
}

template<>
struct KeyType<Reflect::Reflect> {
    using type = Reflect::KeyType;
};

...然后使用KeyType<Reflect::Reflect>,这是一种类型,而不是KeyType,这是一个模板。请注意,您仍可以在界面上使用KeyType(模板);你只需要反思std::is_same<>。另请注意,这需要您为每种类型编写反射 - 虽然这对于宏来说是微不足道的。此外,您不能将Reflect::Reflect用作键类型。 (你可以通过特征以另一种方式做到这一点,但是你会专注于特征的命名空间,这对于多个文件来说有点棘手。)

#define REFLECT_TEMPLATE(TEMPL) \
    namespace Reflect {                \
        struct TEMPL {};               \
    };                                 \
    template<>                         \
    struct TEMPL<Reflect::Reflect> {   \
        using type = Reflect::KeyType; \
    };

如果我是你,我还会在反映的类型中添加const char* name() const ...

答案 1 :(得分:1)

不要将模板用作元编程原语。使用类型。类似,避免使用值。

template<template<class...>class Z>
struct ztemplate{
  template<class...Ts>
  using apply=Z<Ts...>;
};
template<class Z, class...Ts>
using apply=typename Z::template apply<Ts...>;
using zapply=ztemplate<apply>;

您永远不会使用原始template,只需使用ztemplate s。

template<class T>
struct KeyType {};
using zKeyType=ztemplate<KeyType>;

C ++元编程可以更好地处理类型。如果你想要对你的类型进行限制(比如它必须是ztemplate),请写SFINAE或伪造概念来强制执行它。

作为奖励,ztemplate是定义模板的。这让你开启了hana风格的元编程。

这意味着您必须规范地包装模板代码,并去除直接模板和值参数(分别替换为ztemplate和整型常量)。但你最终会得到更强大的元编程。

而不是X<Blah>apply<zX, Blah>。实际上,apply成为您直接使用的唯一模板。

注意apply<zapply, zX, Blah>apply<zapply, zapply, zX, Blah>等与apply<zX, Blah>相同。