2015-01-03 32 views
1

下面是我有的代码的简化版本。调用类<T>的私人构造函数从类<U>

#include <vector> 
#include <algorithm> 

template <typename T> struct Foo { 
    using Value = T; 
    constexpr Foo() = delete; 
    constexpr Foo(T v) : value(v) {} 
    T value; 
}; 

template <typename T> struct Vec { 
    using Elem = Foo<T>; 
    using Container = std::vector<Elem>; 

    Vec() = delete; 
    template <typename... Elems> 
    Vec(Elem a, Elem b, Elems... rest) 
     : elems_{a, b, rest...} {} 

    void add(const Elem &e) { elems_.push_back(e); } 

    template <typename F> auto map(const F &f) const; 

private: 
    Vec(Container &&c) : elems_(std::move(c)) {} 
    Container elems_; 
}; 

template <typename C> 
template <typename F> 
auto Vec<C>::map(const F &f) const { 
    using ReturnedFoo = decltype(f(std::declval<typename Vec<C>::Elem>())); 
    using ValueType = typename ReturnedFoo::Value; 
    using Container = typename Vec<ValueType>::Container; 
    Container mapped_elems; 
    mapped_elems.reserve(elems_.size()); 
    std::transform(elems_.begin(), elems_.end(), std::back_inserter(mapped_elems), 
       f); 
    return Vec<ValueType>{std::move(mapped_elems)}; 
} 

Foo<int> mul2(Foo<int> x) { 
    return Foo<int>{2 * x.value}; 
} 
Foo<double> to_d(Foo<int> x) { 
    return Foo<double>{static_cast<double>(x.value)}; 
} 

int main() { 
    constexpr auto f1 = Foo<int>(1); 
    constexpr auto f2 = Foo<int>(2); 
    constexpr auto f3 = Foo<int>(3); 
    const auto v1 = Vec<int>{f1, f2, f3}; 
    const auto v2 = v1.map(mul2); 
    // const auto v3 = v1.map(to_d); // call to private constructor from here 
} 

我类Vec<T>内部保持Foo<T>类型的元素在std::vector,它总是保持至少2个元素。

我写了一个map函数,它映射/转换每个元素并返回一个新的Vec对象。对于不改变元素类型的映射函数(F : (T) -> T),如mul2一切正常。但是一般情况下(F : (T) -> U)不起作用,因为有一个来自Vec<T>::map函数的类Vec<U>中的私有构造函数的调用。公开这个构造函数将使创建Vec对象的元素少于2个成为可能,所以这不是我想要的。

我解决这一问题的首次尝试是

template <typename X> friend class Vec<X>; 

,但现在看来,这是不允许的。这里是铿锵++的输出:

vec.cpp:23:14: error: partial specialization cannot be declared as a friend 
     friend class Vec<X>; 

有没有办法让它工作? 在写这个问题,我想出了重写地图作为最后一行的想法:

Vec<ValueType> result{mapped_elems[0], mapped_elems[1]}; 
    for (auto it = mapped_elems.begin() + 2 ; it != mapped_elems.end(); ++it) { 
     result.add(*it); 
    } 
    return result; 

但有另一种方式?

(顺便说一句我已经铛3.5.0和g ++ 4.9.2)

+0

你朋友的声明应该是'template 朋友struct vec;' –

回答

3

如果你想要的任何Vec专业化成为朋友目前Vec<T>实例中,朋友的声明应该是:而不是

template <typename X> friend struct Vec; 
//         ^ok, plain identifier 

template <typename X> friend class Vec<X>; 
//         ^~~ wrong! 

§11.3[class.friend]/P3:

朋友声明未声明的函数应具有下列形式之一:

friend elaborated-type-specifier ; 
friend simple-type-specifier ; 
friend typename-specifier ; 

[注:朋友声明可能是声明模板声明(第14,14.5.4条).- 注完]

您目前使用的Vec部分专业化,这是由§14.5.4[临时禁止的声明相匹配的语法。朋友]/p8:

朋友声明不应声明部分专业化。

+1

真是个愚蠢的错误,谢谢! – sawyer

2

你刚才打错friend语法有:

template <typename U> friend struct Vec; 
相关问题