gpt4 book ai didi

c++ - 根据运行时参数创建专用类的实例

转载 作者:搜寻专家 更新时间:2023-10-31 01:42:51 26 4
gpt4 key购买 nike

下面是演示这个想法的代码:

struct A
{
};

struct B
{
};

template<typename T1, typename T2>
struct Specific
{
T1 t1;
T2 t2;

void DoSomething() {}
};

template<typename T1, typename T2>
Specific<T1, T2> create_specific()
{
return Specific<T1, T2>();
}

void my_func(int type1, int type2)
{
if (type1 == 1 && type2 == 1)
{
auto specific = create_specific<A, A>();
specific.DoSomething();
}
else if (type1 == 1 && type2 == 2)
{
auto specific = create_specific<A, B>();
specific.DoSomething();
}
else if (type1 == 2 && type2 == 1)
{
auto specific = create_specific<B, A>();
specific.DoSomething();
}
else if (type1 == 2 && type2 == 2)
{
auto specific = create_specific<B, B>();
specific.DoSomething();
}
}

因此 my_func 参数控制它将用于DoSomething 的类型。这种方法的问题是 if 条件的数量将呈指数增长。我正在寻找一种让编译器为我做这件事的方法。如果我可以为每个类型插槽拆分逻辑,那就太好了:

if (type1 == 1) 
{
create_specific1<A>(...);
}
....
if (type2 == 2)
{
create_specific2<B>(...);
}

有可能吗?

更新

有什么方法可以在 C++11 中实现模板魔法,特别是在 Visual C++ 2013 中?

最佳答案

一种方法是使用这样的查找表。

void (*arr[2][2])() =
{
[] { create_specific<A, A>().DoSomething(); },
[] { create_specific<A, B>().DoSomething(); },
[] { create_specific<B, A>().DoSomething(); },
[] { create_specific<B, B>().DoSomething(); }
};

arr[type1-1][type2-1]();

您也可以让编译器为您生成它。这适用于两种类型:

template <std::size_t...> struct index_list {using type = index_list;};

template <typename, typename> struct concat;
template <std::size_t... i, std::size_t... j> struct concat<index_list<i...>, index_list<j...>> : index_list<i..., j...> {};

// inefficient linear recursive method:
template <std::size_t N>
struct make_index_list : concat<typename make_index_list<N-1>::type, index_list<N>> {};
template <>
struct make_index_list<0> : index_list<0> {};

template <typename A, typename B = A,
typename = typename make_index_list<std::tuple_size<A>::value
* std::tuple_size<B>::value - 1>::type>
class create_lookup;

template <typename ... First, typename... Second, std::size_t... indices>
class create_lookup<std::tuple<First...>, std::tuple<Second...>, index_list<indices...>>
{
template <typename T, typename U>
static void work()
{
create_specific<T, U>().DoSomething();
}

public:

static constexpr void (*arr[sizeof...(First)][sizeof...(Second)])() =
{
work< typename std::tuple_element<indices / sizeof...(First), std::tuple<First...>>::type,
typename std::tuple_element<indices % sizeof...(Second), std::tuple<Second...>>::type >...
};
};

template <typename ... F, typename... S, std::size_t... I>
constexpr void (*create_lookup<std::tuple<F...>, std::tuple<S...>, index_list<I...>>::arr[sizeof...(F)][sizeof...(S)])();

int main()
{
auto arr = create_lookup<std::tuple<A, B>>::arr;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
{
std::cout << i << ' ' << j << ": ";
arr[i][j]();
}
}

从 C++14 开始,您还可以使用 lambda 作为扩展模式,而不是函数模板 (work)。和 std::make_index_sequence , 和 std::tuple_element_t ... ;)

DoSomething 函数设置为

void DoSomething()
{
std::cout << typeid(T1).name() << ' ' << typeid(T2).name() << '\n';
}

产生以下输出:

0 0: A A
0 1: A B
1 0: B A
1 1: B B

泛化到更多类型

此代码适用于任意数量的串联,由模板参数 depth 指定。包含示例,使用 GCC 的 demangle 函数。

#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <tuple>
#include <cxxabi.h>

template<typename... T>
struct Specific
{
void DoSomething()
{
int status;
std::initializer_list<bool> { std::cout << abi::__cxa_demangle(typeid(T).name(), 0, 0, &status) << ' '... };
//std::initializer_list<bool> { std::cout << typeid(T).name() << ' '... };
std::cout << '\n';
}
};

template<typename... T>
Specific<T...> create_specific()
{ return {}; }

template <std::size_t...> struct index_list {using type = index_list;};

template <typename, typename> struct concat;
template <std::size_t... i, std::size_t... j> struct concat<index_list<i...>, index_list<j...>> : index_list<i..., j...> {};

template <std::size_t N>
struct make_index_list : concat<typename make_index_list<N-1>::type, index_list<N>> {};
template <>
struct make_index_list<0> : index_list<0> {};

constexpr std::uintmax_t ipow( std::uintmax_t base, unsigned exp )
{
return exp == 0? 1 : base*ipow(base, exp-1);
}

template <typename T, std::size_t len, std::size_t dim>
struct construct_array
{
using type = typename construct_array<T, len, dim-1>::type[len];
};

template <typename T, std::size_t len>
struct construct_array<T, len, 1>
{
using type = T[len];
};

template <std::size_t depth,
typename A,
typename = typename make_index_list<ipow(std::tuple_size<A>::value, depth)- 1>::type>
class create_lookup;

template <std::size_t depth, typename ... First, std::size_t... indices>
class create_lookup<depth, std::tuple<First...>, index_list<indices...>>
{
template <typename... Args>
static void work()
{
create_specific<Args...>().DoSomething();
}

static constexpr auto length = sizeof...(First);

template <std::size_t index, typename = typename make_index_list<depth-1>::type>
struct get_ptr;

template <std::size_t index, std::size_t ... type_indices>
struct get_ptr<index, index_list<type_indices...>>
{
static constexpr auto value =
work< typename std::tuple_element<index / ipow(length, depth-type_indices-1) % length, std::tuple<First...>>::type... >;
};

public:

static constexpr typename construct_array<void(*)(), length, depth>::type arr
{
get_ptr<indices>::value...
};
};

template <std::size_t depth, typename ... F, std::size_t... I>
constexpr typename construct_array<void(*)(), create_lookup<depth, std::tuple<F...>, index_list<I...>>::length, depth>::type
create_lookup<depth, std::tuple<F...>, index_list<I...>>::arr;

struct A {};
struct B {};
struct C {};

int main()
{
auto arr = create_lookup<3, std::tuple<A, B, C>>::arr;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k)
{
std::cout << i << ' ' << j << ' ' << k << ": ";
arr[i][j][k]();
}
}

可以找到相同的代码但没有 constexpr here .

关于c++ - 根据运行时参数创建专用类的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26193476/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com