2016-06-14 81 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; 
}