friend方法的参数列表中的不同模板特化

时间:2014-02-05 16:35:05

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

我正在尝试创建一个方法,它接受类模板的两个(不同)特化实例,并在编译时返回从模板特化推导出的类型的值。

到目前为止(最小的情况)

#include <iostream>
#include <utility>

template<typename T> class box
{
protected:
    T value;
public:
    box(T value)
    {
        this->value = value;
    }
    friend std::ostream& operator<<(std::ostream& os, box<T>& obj)
    {
        return os << obj.value;
    }

    template<typename K> friend auto operator+(
        const box<T>& left, const box<K>& right) ->
            box<decltype(std::declval<T>() + std::declval<K>())>
    {
        typedef decltype(std::declval<T>() + std::declval<K>()) result_type;
        return box<result_type>(left.value + right.value);
    }
};

int main()
{
    box<int> int_container = box<int>(2);
    box<float> float_container = box<float>(7.0);
    auto another_one = int_container + float_container;
    std::cout << int_container << " " << float_container << " " << another_one << std::endl;
}

这不会编译(通过gcc)直到我公开field值。我想,编译器不能(或不会)将container<K>视为具有声明的运算符的朋友。

当然,我可以为value添加一个公共getter。

其他解决方案是通过将template<typename> friend class box;添加到类定义的开头并使运算符成为类成员而不是friend来使此模板的所有特化都成为朋友。但是,如果我决定创建一个没有这种替代方法的friend方法,那么这种方法就行不通了。 (将所有特化项成为朋友而不将操作符重新定义为类成员的编译原因与原始情况相同。)

因此有一种方法可以使方法模板成为所有类模板的特殊化的朋友,以防它的模板参数在其中一个参数中使用&#39;类型定义?

1 个答案:

答案 0 :(得分:1)

由于每个操作员都需要成为每个模板专业化的朋友,因此您需要保留两个模板参数。我还发现你需要在课堂外移动定义,虽然我不完全确定原因:

template <typename T>
class box
{
    // ...

    template <typename A, typename B>
    friend
    auto operator+(const box<A>& left, const box<B>& right) -> box<decltype(std::declval<A>() + std::declval<B>())>;
};

template <typename A, typename B>
auto operator+(const box<A>& left, const box<B>& right) -> box<decltype(std::declval<A>() + std::declval<B>())>
{
  return { left.value + right.value };
}

顺便说一句,您可以使用更简单,更易读的auto -> decltype或C ++ 14 box<typename std::common_type<A, B>::type>来代替繁琐的box<std::common_type_t<A, B>>构造。