【问题标题】:Interface class for classes with templated function具有模板化函数的类的接口类
【发布时间】:2012-09-06 13:10:15
【问题描述】:
class Foo1: public IFoo
{
public:
    template <class T>
    std::vector<T> foo()
    {
        return std::vector<T>();
    }
};

class Foo2: public IFoo
{
public:
    template <class T>
    std::vector<T> foo()
    {
        return std::vector<T>();
    }
};

如何为上面的两个实现定义一个通用的接口类,以便为这个接口定义std::vector&lt;T&gt; foo()?忽略函数的实现是相同的。

更新:

我正在编写一个 Container 类,它表示通过 C api 发送给我的数据。

我的 Container 实例将存储给定类型的数据,例如 Container&lt;int&gt;, Container&lt;std::string&gt; and Container&lt;Foo&gt;

C api 以一种非常尴尬的方式返回数据,将来可能会改变。有可能我可以将数据复制到例如 std::list 或 std::vector 中,但由于从 C api 传递的数据如此之多,因此尚不清楚这是否可以。

因此,Container 类应该独立于数据的实际存储方式。我使用传递给构造函数的 Getter 和 Setter 类来实现这一点,如下所示:

Container<int>(Getter1<int>(uglyCApiContainer),Setter1<int>(uglyCApiContainer));

因此如果我放弃处理C api如何存储数据的Getter1和Getter2,我只需要更改Containers的创建即可。

但是,我对这种设计有疑问。类型 Foo。

Foo 是一种复杂类型,它自身包含一组容器。目前它看起来像这样:

class Foo
{
public:
        ...
    template <class V>
    Container<V> getMember(std::string& memberName)
};

所以一个给定的 Foo 可以有一组不同类型的容器。我事先知道这些成员的类型,因为它们存储在模型中。 Foo 目前是丑陋的 C api 内存实现的包装器,但我也想为 Foo 分离内存表示,就像我为容器所做的那样。

我不确定如何让 Foo 摆脱其内存实现。我的一个想法是让 getMember 虚拟化,以便引入可能不同的实现,但这对于模板化函数是不可能的。

【问题讨论】:

  • 鉴于函数相同,只需将整个函数移入基类即可。
  • 做一个代表你的问题的例子。
  • @BartekBanachewicz:不幸的是,虚拟模板要等到 C++ 之后才能使用。
  • @BartekBanachewicz:函数模板不能是虚拟的,所以这些不能直接覆盖任何东西。
  • 我怀疑你想要一些 foo() 方法成为接口的一部分,但如果它是模板化的,你就不能这样做。

标签: c++ templates


【解决方案1】:

这是一个使用标签调度和虚拟继承的解决方案:

#include <vector>

template<typename T> struct tag {};

template<typename T> class IFooImpl {
public:
    virtual std::vector<T> getImpl(tag<T>) = 0;
};

class IFoo: public virtual IFooImpl<char>, virtual IFooImpl<int>
{
public:
    template<typename T> std::vector<T> get() {
        return static_cast<IFooImpl<T> *>(this)->getImpl(tag<T>{});
    }
};

template<typename T>
class FooImpl: public virtual IFooImpl<T> {
public:
    std::vector<T> getImpl(tag<T>) { return {}; }
};

class Foo: public IFoo, FooImpl<char>, FooImpl<int> {
};

int main() {
    Foo().get<char>();
}

在所支持的类型(此处为charint)中存在一些重复,但可以通过可变模板继承来避免这种情况:

#include <vector>

template<typename T> struct tag {};

template<template<typename> class C, typename... Types> class Inherit {};
template<template<typename> class C, typename T, typename... Rest>
class Inherit<C, T, Rest...>: public C<T>, Inherit<C, Rest...> {};

template<typename T> class IFooImplV {
public:
    virtual std::vector<T> getImpl(tag<T>) = 0;
};
template<typename T> class IFooImpl: public virtual IFooImplV<T> {};

template<typename... Types> class IFoo: public Inherit<IFooImpl, Types...> {
public:
    template<typename T> std::vector<T> get() {
        return static_cast<IFooImpl<T> *>(this)->getImpl(tag<T>{});
    }
};

template<typename T> class FooImpl: public IFooImpl<T> {
public:
    std::vector<T> getImpl(tag<T>) { return {}; }
};

template<typename... Types> class FooMulti:
    public IFoo<Types...>, Inherit<FooImpl, Types...> {};
class Foo: public FooMulti<char, int> {};

int main() {
    Foo().get<char>();
}

【讨论】:

  • 感谢您的回复!关于你答案的前半部分, FooImpl::getImpl(tag) 如何从 Foo 访问数据。例如,如果 Foo 有一个特定成员变量的设置器,并且该变量需要中继到 FooImpl::getImpl(tag)。
  • @Baz 您可以在虚拟基类或 CRTP 上使用虚拟方法(编译时多态性,即 Foo 上的模板 FooImpl 以及 static_cast thisFoo * .)
猜你喜欢
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-18
  • 1970-01-01
相关资源
最近更新 更多