我想知道是否有一種實用的方法可以使用 C 17 標準撰寫類似以下代碼的內容:
#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.
或者是嗎?
uj5u.com熱心網友回復:
不幸的是,通過編譯時檢查來做到這一點是不可行的。但是,您可以通過運行時檢查提供該功能。
地圖的值型別只能是一種型別,并且Foo<T>每個型別都是不同的型別T。但是,我們可以通過為每個Foo<T>基類提供一個公共基類、擁有指向它的指標映射并使用虛函式分派call()到適當的子類來解決這個問題。
盡管如此,引數的型別也必須始終相同。正如@MSalters 所提到的,std::any可以幫助解決這個問題。
最后,我們可以使用 pimpl 模式包裝所有內容,使其看起來只有一個簡潔的Foo型別:
#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);
}
在 Godbolt 上看到
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/347512.html
上一篇:函式模板特化,不改變原型
下一篇:抽象類中的C 迭代器引數
