2016-06-14 52 views
2

我想重載模板結構中使用朋友的函數。 我想用它來將一個類型映射到另一個類型。在下面的代碼中,我想將int類型映射到MyType模板的朋友功能:錯誤的函數調用

這裏就是我所做的迄今:

void map(...){} // Worst case 

// Here's the class that will overload our function 
template<typename Type, typename T> 
struct MakeFunction { 
    friend Type map(T) { return {}; } 
}; 

// Make the function with int? 
struct MyType : MakeFunction<MyType, int> {}; 

int main() { 
    // The type obtained is void, worst case choosed. The expected result is `MyType` as return type. 
    std::cout << typeid(decltype(map(int{}))).name() << std::endl; 

    return 0; 
} 

然後,我試過了:

template<typename T> 
void map(){} // Worst case 

// Here's the class that will overload our function 
template<typename Type, typename T> 
struct MakeFunction { 
    // Compilation error. 
    friend Type map<T>() { return {}; } 
}; 

struct MyType : MakeFunction<MyType, int> {}; 

int main() { 
    std::cout << typeid(decltype(map<int>())).name() << std::endl; 

    return 0; 
} 

但是編譯與失敗:

error: defining explicit specialization ’map<T>’ in friend delcaration 

如何更改聲明所以選擇正確的功能?或者有沒有一種方法可以在沒有許多模板的情況下映射類型?

+0

注意:友情不是遺傳的(根據* 11.3/10 [class.friend] *)。 – Holt

+0

你可以在'MakeFunction'外面定義'map'嗎? – Holt

+0

在'MakeFunction'內定義它就是一個重點。我想在每次擴展時映射一個類型。在我的例子中,由於'MyType'擴展了它,它應該使用指定類型的函數'map'。 –

回答

3

下面的代碼演示瞭如何定義一個宏DEFINE_TYPE_MAPPING滿足您的需求(這在一定程度上表明瞭想法草圖):

#include <iostream> 
#include <typeinfo> 

void map(...){} // Worst case 

template<class T> struct TypeMapping; 

template<class T> 
typename TypeMapping<T>::type map(const T&); 

#define DEFINE_TYPE_MAPPING(T, U) \ 
    template<> struct TypeMapping<T> { typedef U type; }; 


struct MyType {}; 

DEFINE_TYPE_MAPPING(int, MyType); 
DEFINE_TYPE_MAPPING(char, float*); 
DEFINE_TYPE_MAPPING(std::ostream, unsigned long); 

int main() { 
    std::cout << typeid(decltype(map(int{}))).name() << std::endl; 
    std::cout << typeid(decltype(map('c'))).name() << std::endl; 
    std::cout << typeid(decltype(map(std::cout))).name() << std::endl; 
    std::cout << typeid(decltype(map(1.0))).name() << std::endl; 

    return 0; 
} 
+0

這會很好地工作。可悲的是,我無法爲此做出宏觀調控。對於那些比我受限制較少的人來說,這是一個很好的答案。 –

+0

您可以看到該宏很短且夠簡單。你能否承擔編寫宏的代碼? – Leon

2

如何:

namespace detail{ 

    // To keep exact type 
    template <typename> struct tag {}; 

    // The mapping 
    float map(tag<char>); 
    MyType map(tag<int>); 
    char map(tag<const int&>); 
    // ... and so on 

} 

template <typename T> 
using map_t = decltype(detail::map(detail::tag<T>{})); 

然後

int main() { 
    std::cout << typeid(map_t<int>).name() << std::endl; 
    std::cout << typeid(map_t<const int&>).name() << std::endl; 
}