2011-09-26 64 views
1

所以我刚刚了解到(谢谢你们)decltype。我现在可以写非常好的载体模板,实际上跑赢valarrays(!):C++更广义的操作员模板

template <typename T, typename U> 
vector<decltype(T()*U())> operator*(const vector<T>& A, const vector<U>& B){ 
    vector<decltype(T()*U())> C = vector<decltype(T()*U())>(A.size()); 
    typename vector<T>::const_iterator a = A.begin(); 
    typename vector<U>::const_iterator b = B.begin(); 
    typename vector<decltype(T()*U())>::iterator c = C.begin(); 
    while (a!=A.end()){ 
    *c = (*a) + (*b); 
    a++; b++; c++; 
    } 
    return C; 
} 

是否有可能使这种模板更是“元”的,在这个意义上,我们允许操作员(“*” )本身是一个模板参数?即有一个适用于*,+,%等的模板定义,其中适当的操作符op用于* c =(* a)op(* b)?

我打赌它不是,但它会很好!

+0

这是本质accumulate'的'二进制版本,虽然'accumulate'本身已经可以用于类似的东西,虽然不完全对称。不过,真正的力量可能来自懒惰评估包装。 –

+0

...几个nitpicks:你可能想要使用'C'和'reserve'的默认构造来确保它不需要增长,然后使用'push_back'(而不是用大小 - 创建大小的数组与'vector c = vector (a.size())' - 并重写元素)。使用typedefs!它们有助于可读性,单个'typedef decltype(A.front()* B.front())result_type'将使代码更具可读性。避免向泛型代码中添加不需要的要求(当前实现使用'T()','U()'和'result_type()'强加一个默认构造函数) –

+0

@DavidRodríguez-dribeas:我发现使用push_back比完整的申报/重写版本慢得多,在我的测试案例中速度降低了50%。 – andyInCambridge

回答

2

如您所料,此答案为“否”。 :)

但是,您可以使用预处理产生这样的功能:

#define OPERATOR_BLOB(optype) \ 
    vector<…> operator optype (…) { … } 

OPERATOR_BLOB(*) 
OPERATOR_BLOB(+) 
… 
+0

谢谢!这似乎是正确的路要走。 – andyInCambridge

0

使用std::declval<T&&>(),而不是仅仅T(),它可能不会有一个默认的构造函数(因为的std ::矢量不需要默认构造函数,只有一个拷贝构造函数)。 非常确定关于&类型参考&右值引用的正确性和转发,对于值,引用,常量引用,右值引用,类可以实现不同的事情。用几个类来测试它。

另外,请注意,由于未实现的功能,返回类型提取可能不适用于GCC中的复合赋值运算符。

是的,我在我的指针包装类参数宏解决它:http://frigocoder.dyndns.org/code/Frigo/Lang/ref

例如

#define PROXY_BINARY_OPERATOR(_) \ 
    template <class Arg> \ 
    decltype(std::declval<T&&>() _ std::declval<Arg&&>()) operator _ (Arg&& arg) \ 
    { \ 
     return std::forward<T>(get()) _ std::forward<Arg>(arg); \ 
    } \ 
    template <class Arg> \ 
    decltype(std::declval<const T&&>() _ std::declval<Arg&&>()) operator _ (Arg&& arg) const \ 
    { \ 
     return std::forward<T>(get()) _ std::forward<Arg>(arg); \ 
    }