首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模板类型擦除

模板类型擦除
EN

Stack Overflow用户
提问于 2021-11-03 22:20:23
回答 1查看 564关注 0票数 1

我想知道是否有一种使用C++17标准编写类似于以下代码的实用方法:

代码语言:javascript
复制
#include <string>
#include <functional>
#include <unordered_map>

template <class Arg>
struct Foo
{
    using arg_type = Arg;
    using fun_type = std::function< void(Arg&) >;
    fun_type fun;
    
    void call( Arg& arg ) { fun(arg); }
};

struct Bar
{
    using map_type = std::unordered_map<std::string,Foo>; // that's incorrect
    map_type map;
    
    auto& operator[] ( std::string name ) { return map[name]; }
};

在上面的代码中,类Foo的模板参数对应于一元函数的输入类型,它不返回任何内容。不同模板类型的Foo的不同实例对应于接受不同类型参数的函数。类Bar只是为了给这些函数分配一个名称,但是很明显,当前的映射声明是不正确的,因为它需要知道Foo的模板类型。

或者是真的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-03 22:38:43

不幸的是,用编译时检查来完成这个任务是不可行的。但是,您可以为该功能提供运行时检查。

映射的值类型只能是一种类型,而Foo<T>是每个T的不同类型。但是,我们可以通过为每个Foo<T>提供一个公共基类、有一个指向它的指针映射以及使用一个虚拟函数将call()分派给适当的子类来解决这个问题。

然而,对于这一点,参数的类型也必须总是相同的。正如@MSalters所提到的,std::any可以在这方面提供帮助。

最后,我们可以使用pimpl模式包装所有这些,这样看起来只有一个整洁的Foo类型:

代码语言:javascript
复制
#include <cassert>
#include <string>
#include <functional>
#include <any>
#include <unordered_map>
#include <memory>

struct Foo {
public:
  template<typename T, typename FunT>
  void set(FunT fun) {
      pimpl_ = std::make_unique<FooImpl<T, FunT>>(std::move(fun));
  }

  // Using operator()() instead of call() makes this a functor, which
  // is a little more flexible.
  void operator()(const std::any& arg) {
      assert(pimpl_);
      pimpl_->call(arg);
  }
  
private:
    struct IFooImpl {
      virtual ~IFooImpl() = default;
      virtual void call( const std::any& arg ) const = 0; 
    };

    template <class Arg, typename FunT>
    struct FooImpl : IFooImpl
    {
        FooImpl(FunT fun) : fun_(std::move(fun)) {}
        
        void call( const std::any& arg ) const override {
            fun_(std::any_cast<Arg>(arg));
        }

    private:
        FunT fun_;
    };

  std::unique_ptr<IFooImpl> pimpl_;
};


// Usage sample
#include <iostream>

void bar(int v) {
    std::cout << "bar called with: " << v << "\n";
}

int main() {
    std::unordered_map<std::string, Foo> table;

    table["aaa"].set<int>(bar);

    // Even works with templates/generic lambdas!
    table["bbb"].set<float>([](auto x) {
        std::cout << "bbb called with " << x << "\n";
    });

    table["aaa"](14);
    table["bbb"](12.0f);
}

看哥德波特

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69832385

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档