以模板化类作为返回值的C++模板化函数

我有这个Java代码:

public interface Adapter<FROM,TO> {
    /**
     * Adapts something from one type to a type. 
     * @param f
     * @return
     */
    public TO adapt(FROM f);
    
    /**
     * Chains adapters. 
     * 
     * @param <NEXT>
     * @param next 
     * @return a new adapter that takes the output of this adapter and 
     * adapts to something of type NEXT.
     */
    public default <NEXT> Adapter<FROM,NEXT> chain(Adapter<TO,NEXT> next){
        Adapter<FROM,TO> x=this; 
        return new Adapter<FROM,NEXT>(){
            @Override
            public NEXT adapt(FROM f) {
                return next.adapt(x.adapt(f));
            }
        };
    }

我真的很喜欢 C++ 中类似的东西。到目前为止,我做得最好的是:

#ifndef ADAPTER_H
#define ADAPTER_H
 
template <typename FROM, typename TO>
class Adapter
{
  public:
  TO adapt(FROM f);
 
  template <typename NEXT> Adapter<FROM, NEXT> chain(Adapter<TO, NEXT> arg)
  {
    class UnNamed: public Adapter<FROM, NEXT>
    {
      public: 
      Adapter<TO, NEXT> outer;
      UnNamed(Adapter<TO, NEXT> arg)
      {
        outer = arg;
      }
      NEXT adapt(FROM from)
      {
         outer.adapt(Adapter::adapt(from));
      }
     };
     return UnNamed(arg);
   }
};
 
#endif

但它因未定义的引用错误而失败。我真的很想让 api 尽可能接近 Java,但我不知道如何让嵌套类以可引用的方式存在。

回答

你很近。

在 Java 中,interfaces 必须由具体类实现,interface方法是虚拟的,必须在这些类中被覆盖。在您的示例中,在方法上使用default关键字chain()允许 Java 生成自己的类来实现返回的Adapter接口chain()

在C++中,你可以做类似的事情,只是没有相当于Java的default关键字(C++有一个default关键字,但它的含义很不一样),所以你需要显式定义你自己的类类型来实现你的虚拟接口。您尝试这样做,但是除非您通过对象的指针/引用调用虚拟方法,否则多态性不起作用,否则您可能会受到对象切片的影响。在某种程度上,Java 也强制执行了这个规则,因为 Java 中的所有对象都是引用类型,只有基本类型是值类型(而在 C++ 中,类也可以用作值类型)。

尝试更像这样的事情:

#include <memory>

template<typename FROM, typename TO>
class Adapter
{
public:
    /**
     * Adapts something from one type to a type. 
     * @param f
     * @return
     */
    virtual TO adapt(FROM f) = 0;
    
    /**
     * Chains adapters. 
     * 
     * @param <NEXT>
     * @param next 
     * @return a new adapter that takes the output of this adapter and 
     * adapts to something of type NEXT.
     */
    template<typename NEXT>
    std::unique_ptr<Adapter<FROM, NEXT>> chain(Adapter<TO, NEXT> *next)
    {
        class ChainedAdapter : public Adapter<FROM, NEXT>
        {
        private:
            Adapter<FROM, TO> *x; 
            Adapter<TO, NEXT> *next;
        public:
            ChainedAdapter(Adapter<FROM, TO> *x, Adapter<TO, NEXT> *next)
                : x(x), next(next) {}

            NEXT adapt(FROM f) override {
                return next->adapt(x->adapt(f));
            }
        };

        return std::make_unique<ChainedAdapter>(this, next);
    }
};

在线演示

虽然,我想你也可以chain()ChainedAdapter不动态创建它的情况下让return 成为一个新的,如果你对返回的对象非常小心并且不以任何方式使用它会切片它:

#include <memory>
     
template<typename FROM, typename TO>
class Adapter
{
public:
    /**
     * Adapts something from one type to a type. 
     * @param f
     * @return
     */
    virtual TO adapt(FROM f) = 0;
     
    /**
     * Chains adapters. 
     * 
     * @param <NEXT>
     * @param next 
     * @return a new adapter that takes the output of this adapter and 
     * adapts to something of type NEXT.
     */
    template<typename NEXT>
    auto chain(Adapter<TO, NEXT> *next)
    {
        class ChainedAdapter : public Adapter<FROM, NEXT>
        {
        private:
            Adapter<FROM, TO> *x; 
            Adapter<TO, NEXT> *next;
        public:
            ChainedAdapter(Adapter<FROM, TO> *x, Adapter<TO, NEXT> *next)
                : x(x), next(next) {}
     
            NEXT adapt(FROM f) override {
                return next->adapt(x->adapt(f));
            }
        };
     
        return ChainedAdapter(this, next);
    }
};

在线演示


以上是以模板化类作为返回值的C++模板化函数的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>