首页 文章

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

提问于
浏览
1

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

到目前为止我所拥有的是(在极少数情况下)

#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;
}

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

当然,我可以为 value 添加公共getter .

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

那么有一种方法可以使方法模板成为所有类模板特化的朋友,以防它的模板参数在其参数的一个类型定义中使用吗?

1 回答

  • 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 };
    }
    

    顺便说一下,您可以使用更简单,更易读的 box<typename std::common_type<A, B>::type> 或C 14 box<std::common_type_t<A, B>> ,而不是繁琐的 auto -> decltype 构造 .

相关问题