我的问题类似于this post,我希望我有多个模板参数和字符串。因此,设置是
class base_class; // no template args
template<typename T, typename U, typename V>
class child_class : public base_class;
T
,U
和V
的实现类型数量有限,我希望在运行时选择三个字符串。因此,作为引用帖子中的问题,我可以做类似
std::unique_ptr<base_class> choose_arg1(
std::string T_str, std::string U_str, std::string v_str){
if(T_str == "int"){
return(choose_arg2<int>(U_str, V_str));
} else if(T_str == "char"){
return(choose_arg2<char>(U_str, V_str));
} // ...
}
template<typename T>
std::unique_ptr<base_class> choose_arg2(std::string U_str, std::string v_str){
if(U_str == "int"){
return(choose_arg3<T, int>(V_str));
} else if(U_str == "char"){
return(choose_arg3<T, char>(V_str));
} // ...
}
template<typename T, typename U>
std::unique_ptr<base_class> choose_arg3(std::string v_str){
if(v_str == "int"){
return(std::make_unique<child_class<T, U, int>>());
} else if(v_str == "char"){
return(std::make_unique<child_class<T, U, char>>());
} // ...
}
但有更好的方法吗?我记录的组合少于5 ^ 3。
答案 0 :(得分:3)
我建议使用几个静态func()
方法
template <typename ... Ts>
struct choose_args_h
{
using retT = std::unique_ptr<base_class>;
template <typename ... Args>
static retT func (std::string const & s, Args const & ... args)
{
if ( s == "int" )
return choose_args_h<Ts..., int>::func(args...);
else if ( s == "char" )
return choose_args_h<Ts..., char>::func(args...);
// else ...
}
static retT func ()
{ return std::make_unique<child_class<Ts...>>(); }
};
所以你可以简单地写一个choose_args()
函数
template <typename ... Args>
std::unique_ptr<base_class> choose_args (Args const & ... args)
{ return choose_args_h<>::func(args...); }
以下是一个完整的工作示例
#include <string>
#include <memory>
class base_class
{ };
template <typename, typename, typename>
class child_class : public base_class
{ };
template <typename ... Ts>
struct choose_args_h
{
using retT = std::unique_ptr<base_class>;
template <typename ... Args>
static retT func (std::string const & s, Args const & ... args)
{
if ( s == "int" )
return choose_args_h<Ts..., int>::func(args...);
else if ( s == "char" )
return choose_args_h<Ts..., char>::func(args...);
// else ...
}
static retT func ()
{ return std::make_unique<child_class<Ts...>>(); }
};
template <typename ... Args>
std::unique_ptr<base_class> choose_args (Args const & ... args)
{ return choose_args_h<>::func(args...); }
int main ()
{
auto p0 = choose_args("int", "char", "int");
auto p1 = choose_args("int", "char", "char");
}
答案 1 :(得分:2)
这篇文章中显示的是一个C ++ 17解决方案,它通过Argmaps
类型对允许的类型和相应的键进行编译时配置。查找由编译时循环完成。
C ++ 11不支持此处使用的编译时循环所需的通用lambda。相反,可以通过模板元编程使用“索引技巧”(如this online demo)执行查找,但这感觉太复杂了,我更喜欢the std::map
approach。请注意,如果密钥不是唯一的,我的链接C ++ 11尝试可以call the constructor twice。
#include <iostream>
#include <memory>
#include <string>
#include "loop.hpp"
template<class... Ts> struct Types {
static constexpr size_t size = sizeof...(Ts);
template<size_t i>
using At = std::tuple_element_t<i, std::tuple<Ts...>>;
};
template<class... Ts> constexpr Types<Ts...> to_types(Ts...) { return {}; }
template<auto... cs> struct Str {
operator std::string() const {
constexpr auto list = std::initializer_list<char>{cs...};
return std::string{list.begin(), list.end()};
}
};
template<class Char, Char... cs>
constexpr auto operator""_c() {
return Str<cs...>{};
}
//////////////////////////////////////////////////////////////////////////////
struct Base {
virtual void identify() const = 0;
};
template<class... Ts>
struct Derived : Base {
virtual void identify() const override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
using Ptr = std::unique_ptr<Base>;
//////////////////////////////////////////////////////////////////////////////
template<class Argmaps, class Args=Types<>>
struct choose_impl;
template<class Map0, class... Maps, class... Args>
struct choose_impl<Types<Map0, Maps...>, Types<Args...>> {
static constexpr size_t pos = sizeof...(Args);
template<class S0, class... Ss>
static Ptr get(S0 s0, Ss... ss) {
Ptr ret{nullptr};
using namespace Loop;
loop(less<Map0::size>, [&] (auto i) {
using Argmapping = typename Map0::template At<i>;
using Key = typename Argmapping::template At<0>;
using Arg = typename Argmapping::template At<1>;
using Recursion = choose_impl<Types<Maps...>, Types<Args..., Arg>>;
if(std::string(Key{}) == s0) ret = Recursion::get(ss...);
});
if(!ret) {
std::cerr << "NOT MAPPED AT POS " << pos << ": " << s0 << std::endl;
std::terminate();
}
return ret;
}
};
template<class... Args>// all Args are resolved
struct choose_impl<Types<>, Types<Args...>> {
static Ptr get() {
return std::make_unique<Derived<Args...>>();
}
};
template<class Argmaps, class... Ss>
Ptr choose(Ss... ss) {
static_assert(Argmaps::size == sizeof...(Ss));
return choose_impl<Argmaps>::get(std::string(ss)...);
}
template<class V, class K>
auto make_argmapping(K) {
return Types<K, V>{};
}
//////////////////////////////////////////////////////////////////////////////
int main() {
using Argmaps = decltype(
to_types(
to_types(// first template parameter
make_argmapping<int>("int"_c),
make_argmapping<char>("char"_c),
make_argmapping<bool>("bool"_c)
),
to_types(// ... second ...
make_argmapping<double>("double"_c),
make_argmapping<long>("long"_c)
),
to_types(// ... third
make_argmapping<bool>("bool"_c)
)
)
);
choose<Argmaps>("int", "double", "bool")->identify();
choose<Argmaps>("int", "long", "bool")->identify();
choose<Argmaps>("char", "double", "bool")->identify();
choose<Argmaps>("char", "long", "bool")->identify();
choose<Argmaps>("bool", "double", "bool")->identify();
choose<Argmaps>("bool", "long", "bool")->identify();
// bad choice:
choose<Argmaps>("int", "int", "bool")->identify();
return 0;
}
来自this unread answer的loop.hpp:
#ifndef LOOP_HPP
#define LOOP_HPP
namespace Loop {
template<auto v> using Val = std::integral_constant<decltype(v), v>;
template<auto i> struct From : Val<i> {};
template<auto i> static constexpr From<i> from{};
template<auto i> struct Less : Val<i> {};
template<auto i> static constexpr Less<i> less{};
// `to<i>` implies `less<i+1>`
template<auto i> struct To : Less<i+decltype(i)(1)> {};
template<auto i> static constexpr To<i> to{};
template<auto i> struct By : Val<i> {};
template<auto i> static constexpr By<i> by{};
template<auto i, auto N, auto delta, class F>
constexpr void loop(From<i>, Less<N>, By<delta>, F f) noexcept {
if constexpr(i<N) {
f(Val<i>{});
loop(from<i+delta>, less<N>, by<delta>, f);
}
}
// overload with two arguments (defaulting `by<1>`)
template<auto i, auto N, class F>
constexpr void loop(From<i>, Less<N>, F f) noexcept {
loop(from<i>, less<N>, by<decltype(i)(1)>, f);
}
// overload with two arguments (defaulting `from<0>`)
template<auto N, auto delta, class F>
constexpr void loop(Less<N>, By<delta>, F f) noexcept {
loop(from<decltype(N)(0)>, less<N>, by<delta>, f);
}
// overload with one argument (defaulting `from<0>`, `by<1>`)
template<auto N, class F>
constexpr void loop(Less<N>, F f) noexcept {
using Ind = decltype(N);
loop(from<Ind(0)>, less<N>, by<Ind(1)>, f);
}
} // namespace Loop
#endif
答案 2 :(得分:2)
正如我在评论中指出的那样,您可以使用字符串的静态映射来运行。
对于您的示例代码(略微简化为2个模板参数以使其更短),这将成为:
#include <iostream>
#include <string>
#include <map>
#include <functional>
#include <memory>
class base_class { }; // no template args
template<typename T, typename U>
class child_class : public base_class { };
using ptr_type = std::unique_ptr<base_class>;
// Declarations
std::unique_ptr<base_class> choose_arg1 (std::string const & T_str,
std::string const & U_str);
template<typename T>
std::unique_ptr<base_class> choose_arg2 (std::string const & U_str);
// Definitions
std::unique_ptr<base_class> choose_arg1 (std::string const & T_str,
std::string const & U_str) {
using function_type = std::function<ptr_type(std::string const &)>;
using map_type = std::map<std::string, function_type>;
static const map_type ptrMap = {
{"int", choose_arg2<int> },
{"char", choose_arg2<char> }
};
auto ptrIter = ptrMap.find(T_str);
return (ptrIter != ptrMap.end()) ? ptrIter->second(U_str) : nullptr;
}
template<typename T>
std::unique_ptr<base_class> choose_arg2 (std::string const & U_str) {
using function_type = std::function<ptr_type()>;
using map_type = std::map<std::string, function_type>;
static const map_type ptrMap = {
{"int", []{ return std::make_unique<child_class<T, int>>(); } },
{"char", []{ return std::make_unique<child_class<T, char>>(); } }
};
auto ptrIter = ptrMap.find(U_str);
return (ptrIter != ptrMap.end()) ? ptrIter->second() : nullptr;
}
int main () {
std::cout << typeid(choose_arg1("int", "char")).name() << "\n";
std::cout << "[Done]\n";
}