2017-01-08 121 views
4

我想在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 

然而,下面的表達式,當與鐺++ 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爲真,並且鐺++,這是錯誤的。

我的問題是:我怎樣才能實現一個模板到模板地圖,將滿足std::is_same要求與g ++和clang ++?我願意使用宏作爲最後的手段...

回答

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 S,只是ztemplate的工作。

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>相同。

+0

非常有趣,謝謝。它需要一些工作,但我認爲這可能是值得的。我不明白的是:爲什麼要引入'zapply'類型?只是提供一個例子嗎? – Kevin

+1

@Kevin嗯,你想用'apply'本身進行元編程,你需要它作爲一個類型而不是模板。 ;)例如,假設您有一個ztemplates列表和一個單獨的類型列表。首先,您生成兩個列表的交叉產品(生成2個元素的列表的列表)。然後你fmap適用於跨產品元素或其他。 – Yakk

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添加到反射類型中...

+0

非常有趣的與停止問題並行,謝謝! – Kevin