我有一個必須實作虛函式的子類,以便呼叫者可以在不知道其具體型別的情況下與其互動。但我想對這個子類進行模板化以使用不同的型別。基本上,這是:
class Base
{
public:
virtual void insert(const std::string & val, const std::string & type_str) = 0;
};
template<typename T>
class C : public Base
{
public:
virtual void insert(const std::string & val, const std::string & type_str) final
{
// Something that tries to convert val to type T and inserts into container;
// Would throw if conversion fails
// e.g.:
if (type_str == "int")
container.insert(std::stoi(val));
else if (type_str == "str")
container.insert(val); // Error: No matching function call to `insert` [...]
}
private:
std::set<T> container;
};
我理解這個問題:任何給定的專業化C都不會有一個接受除T;以外的型別的容器。這只是一個運行時保證,沒有人C::insert()用錯誤的型別呼叫。
有沒有辦法解決?我想為這個子類保留與從 Base 繼承的其他子類相同的介面,這需要接受字串并在內部進行轉換。
非常高興有一個 C 20 解決方案(使用概念來解決這個問題有一些失敗的嘗試......)。如果重要的話,我正在使用 gcc。
uj5u.com熱心網友回復:
您可以使用if constexpr(C 17 及更高版本):
#include <type_traits>
class Base
{
public:
virtual void insert(const std::string & val, const std::string & type_str) = 0;
};
template<typename T>
class C : public Base
{
public:
virtual void insert(const std::string & val, const std::string & type_str) final
{
if constexpr(std::is_same_v<T,int>){
assert(type_str == "int"); // or you can just drop this, depend on what you want
container.insert(std::stoi(val));
}
else if constexpr(std::is_same_v<T,std::string>){
assert(type_str == "str");
container.insert(val);
}
else{
static_assert(!std::is_same_v<T,T>,"not supported conversion");
}
}
private:
std::set<T> container;
};
或者,您可以改用模板特化。
uj5u.com熱心網友回復:
對于 C 20 概念解決方案,您可以將insert邏輯分解為輔助函式并添加requires子句以確保T可轉換為type_str運行時給出的型別。例如:
template <typename T>
T parse(const std::string& val, const std::string& type_str)
requires std::convertible_to<T, int>
{
if (type_str != "int") {
throw std::runtime_error("can't convert to int");
}
return std::stoi(val);
}
template <typename T>
T parse(const std::string& val, const std::string& type_str)
requires std::convertible_to<T, std::string>
{
if (type_str != "str") {
throw std::runtime_error("can't convert to str");
}
return val;
}
template<typename T>
class C : public Base
{
public:
virtual void insert(const std::string & val, const std::string & type_str) final
{
container.insert(parse<T>(val, type_str));
}
private:
std::set<T> container;
};
演示
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/515150.html
標籤:C 哎呀模板遗产c 20
