【问题标题】:template friend function: wrong function called模板友元函数:调用了错误的函数
【发布时间】:2016-06-14 06:21:31
【问题描述】:

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

如何更改声明以便选择正确的函数?或者有没有办法在没有大量样板的情况下映射类型?

【问题讨论】:

  • 注意:友谊不会被继承(根据 11.3/10 [class.friend])。
  • 你能在MakeFunction之外定义map吗?
  • MakeFunction 中定义它是重点。我想在每次扩展时映射一个类型。在我的示例中,由于 MyType 扩展了它,它应该使具有指定类型的函数 map 可用。
  • @GuillaumeRacicot 这行不通,因为如果在类中定义的友元函数仅在该范围内可见。如果你想让它在外面可见,那么你必须把它放在那个范围内,在你的情况下是全局的。
  • 我之前在全局范围内声明了它,但这迫使我的库的用户手动添加它。相反,我想提供 MakeFunction 结构,以便我的库的用户可以扩展以在“类型映射”中添加类型

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


【解决方案1】:

下面的代码展示了如何定义一个宏 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;
}

【讨论】:

  • 这会很好用。可悲的是,我负担不起为此制作宏。对于那些限制比我少的人来说,这是一个很好的答案。
  • 可以看到这个宏很短很简单。你能负担得起编写宏的底层代码吗?
【解决方案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;
}

【讨论】:

    猜你喜欢
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    • 2011-07-15
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多