模板友好功能:调用错误函数

时间:2016-06-14 06:21:31

标签: c++ templates c++11 friend

我正在尝试使用friend重载模板结构中的函数。 我想用它来将类型映射到另一种类型。在下面的代码中,我想将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

如何更改声明以便选择正确的功能?或者有没有办法在不使用样板的情况下映射类型?

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分: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;
}