1

我非常希望能够提供一个仿函数作为模板参数。函子必须能够提供“他们自己”作为该参数。

我想象这样的事情:

template<typename T, template<typename> class SumFunctor> class foo;

template<typename T>
struct sum_default
{
    foo<T, sum_default> operator()(foo<T, sum_default> a, foo<T, sum_default> b) const 
    {
            T a_data = a.data();
            T b_data = b.data();
            return foo<T, sum_default>(a_data + b_data);
    }
};

template<typename T>
struct sum_awesome
{
    foo<T, sum_awesome> operator()(foo<T, sum_awesome> a, foo<T, sum_awesome> b) const 
    {
            T a_data = a.data();
            T b_data = b.data();
            return foo<T, sum_awesome>(a_data - b_data);
    }
};

template<typename T=int, template<typename> class SumFunctor=sum_default>
class foo
{
private:
    T _data;
    SumFunctor<T> _functor;
public:
    foo<T, SumFunctor>(T data) : _data(data) {}

    T data() { return _data; }

    friend const foo operator +(const foo& lhs, const foo& rhs)
    {
            return lhs._functor(lhs,rhs);
    }
};

int main(){
    foo<> a(42); 
    foo<double> b(1.0);
    foo<double,sum_default> c(4.0);
    foo<double,sum_awesome> d(4.0);

    a+a;
    d+d;
}

这可能吗?如果可以,怎么做?

另一种解决方案是向构造函数提供函子,但我认为这非常难看,因为用户必须自己动态分配函子(因为我们无法确定构造函数中函子的类型。使用 RTTI 这样做似乎有点丑):

foo<double> a(42, new sum_default<double>() );

这也强制所有函子从一些预定义的基本函子派生。

更新

尝试将模板参数添加到 sum_default 模板参数似乎无法解决问题:

template<typename T>
struct sum_default
{
// Error    1   error C3200: 'sum_default<T>' : invalid template argument for template parameter 'SumFunctor', expected a class template
foo<T, sum_default<T> > operator()(foo<T, sum_default<T> > a, foo<T, sum_default<T> > b) const 
{
    T a_data = a.data();
    T b_data = b.data();
    return foo<T, sum_default<T> >(a_data + b_data);
}
};
4

1 回答 1

3

在这里咬你的东西被称为“类名注入”——在类模板内部,例如Foo<T>,不合格的使用Foo实际上被视为Foo<T>. 引用 C++11 §14.6.1/1:

与普通(非模板)类一样,类模板具有注入类名称。注入的类名可以用作模板名类型名。当它与template-argument-list一起使用时,作为模板模板参数的模板参数,或作为朋友类模板声明的详细类型说明符中的最终标识符,它指的是类模板本身. 否则,它等价于template-name后跟包含在 中的类模板的模板参数<>

因此,在 内部sum_default<T>,当您拥有 时foo<T, sum_default>,它会被视为您键入了foo<T, sum_default<T> >(这显然不能像foo需要模板模板参数那样工作)。

为了避免这种行为,您需要限定这些类模板中类模板名称的使用。因为您的类模板在全局范围内,::所以就足够了:

template<typename T>
struct sum_default;

template<typename T = int, template<typename> class SumFunctor = sum_default>
class foo
{
    T _data;
    SumFunctor<T> _functor;

public:
    foo<T, SumFunctor>(T data) : _data(data) { }

    T data() { return _data; } const

    friend foo operator +(foo const& lhs, foo const& rhs)
    {
        return lhs._functor(lhs, rhs);
    }
};

template<typename T>
struct sum_default
{
    foo<T, ::sum_default> operator ()(foo<T, ::sum_default> a,
                                      foo<T, ::sum_default> b) const
    {
        return foo<T, ::sum_default>(a.data() + b.data());
    }
};

template<typename T>
struct sum_awesome
{
    foo<T, ::sum_awesome> operator()(foo<T, ::sum_awesome> a,
                                     foo<T, ::sum_awesome> b) const
    {
        return foo<T, ::sum_awesome>(a.data() - b.data());
    }
};

int main()
{
    foo<> a(42);
    foo<double> b(1.0);
    foo<double, sum_default> c(4.0);
    foo<double, sum_awesome> d(4.0);

    a + a;
    d + d;
}

请注意,这也允许您因此定义foo的构造函数,从而减少一些噪音:

foo(T data) : _data(data) { }
于 2012-04-26T18:38:58.483 回答