【问题标题】:Template functors which must provide themself as a template arguments必须提供自己作为模板参数的模板函子
【发布时间】:2012-04-26 18:10:47
【问题描述】:

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

我想像这样:

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

【问题讨论】:

  • 感谢您的回复,但您的建议无法编译。
  • 好的。我将错误添加到问题中。如果您能就如何修正我的定义顺序提供帮助,将不胜感激。
  • 对不起,我最初误解了您的代码的意图。对不起,噪音。 :-]

标签: c++ templates constructor functor


【解决方案1】:

这里的问题被称为“类名注入”——在类模板内部,例如Foo&lt;T&gt;,对Foo的不合格使用实际上被视为Foo&lt;T&gt;。引用 C++11 §14.6.1/1:

与普通(非模板)类一样,类模板具有注入类名称。注入的类名可以用作 template-nametype-name。当它与 template-argument-list 一起使用时,作为模板 template-parametertemplate-argument,或作为最终标识符在友元类模板声明的elaborated-type-specifier中,它指的是类模板本身。否则,它相当于 template-name 后跟 &lt;&gt; 中包含的类模板的 template-parameters

因此,在sum_default&lt;T&gt; 内部,当您有foo&lt;T, sum_default&gt; 时,它会被视为您键入了foo&lt;T, sum_default&lt;T&gt; &gt;(这显然不会起作用,因为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) { }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多