Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;组合模板展开_C++_Templates - Fatal编程技术网

C++ C++;组合模板展开

C++ C++;组合模板展开,c++,templates,C++,Templates,我想从库中请求一系列数据,这需要我指定两种类型: class a; class b; class c; template<typename A, typename B> void get() {....} void get_all() { get<a,a>() get<a,b>() get<a,c>() get<b,a>() get<b,b>() // etc... } a类; 乙级;; 丙级;;

我想从库中请求一系列数据,这需要我指定两种类型:

class a;
class b;
class c;
template<typename A, typename B> void get() {....}

void get_all() {
  get<a,a>()
  get<a,b>()
  get<a,c>()
  get<b,a>()
  get<b,b>()
  // etc...
}
a类;
乙级;;
丙级;;
模板void get(){..}
void get_all(){
得到()
得到()
得到()
得到()
得到()
//等等。。。
}
我想为一组类的每一个组合调用get函数(大约10个不同的变体)——这意味着大约100个不同的调用。我不想手工编写所有这些get()调用的代码

有没有办法自动生成这些调用?我想我可以使用预处理器宏,但我很好奇是否有办法生成这样一个组合列表,给定a,b,c,d,。。。通过使用模板代码

编辑:小麻烦:事实上,这都在一个成员函数中

template<typename A, typename B> 
void Getter::get() 
{  
  auto assn = fMemberObject->RetrieveAllDataOfType<association<A,B>();
  .. do stuff with assn ...
}

void Getter::get_all() {
  get<a,a>();
}
模板
void Getter::get()
{  

auto assn=fMemberObject->RetrieveAllDataOfType更新了以处理新的需求,即不能使用相同的类型参数调用
get()
,并且
get()
是类成员函数。我在这里调用了类
管理器


您可以(ab)使用C++11可变模板来实现这一点。可能有一种更简洁的方法来实现这一点,但它可以工作并且(希望)可以理解:

struct manager
{
    // Sample implementation of get(), showing the names of the types.
    template <typename A, typename B>
    void get() {
        std::cout << "A=" << typeid(A).name() << " B=" << typeid(B).name() << '\n';
    }
};

// Implementation, uses variadic templates with recursion.
namespace detail
{
    // Helper to delimit template parameter packs.
    template <typename...> struct pack;

    // Terminating case, <=1 type argument(s) means we are done.
    template <typename...>
    struct call_get_all_beta
    {   
        static void call(manager &) { }
    };

    // Invoke get<First, Second>() and recurse with <First, Tail...>.
    template <typename First, typename Second, typename... Tail>
    struct call_get_all_beta<First, Second, Tail...>
    {   
        static void call(manager &m) {
            m.get<First, Second>();
            call_get_all_beta<First, Tail...>::call(m);
        }
    };

    // Specialization to handle skipping over types that are the same.
    template <typename First, typename... Tail>
    struct call_get_all_beta<First, First, Tail...>
    {   
        static void call(manager &m) {
            call_get_all_beta<First, Tail...>::call(m);
        }
    };

    template <typename...>
    struct call_get_all_alpha;

    // Terminating case, first pack is empty.
    template <typename... B>
    struct call_get_all_alpha<pack<>, pack<B...>>
    {   
        static void call(manager &) { }
    };

    // Pass <FirstA, B...> on to call_get_all_beta, recurse with
    // <pack<TailA...>, pack<B...>>.
    template <typename FirstA, typename... TailA, typename... B>
    struct call_get_all_alpha<pack<FirstA, TailA...>, pack<B...>>
    {   
        static void call(manager &m) {
            call_get_all_beta<FirstA, B...>::call(m);
            call_get_all_alpha<pack<TailA...>, pack<B...>>::call(m);
        }
    };
}

// Helper to call the implementation detail.
template <typename... Types>
void get_all_permutations(manager &m)
{
    detail::call_get_all_alpha<detail::pack<Types...>, detail::pack<Types...>>::call(m);
}
结构管理器 { //get()的示例实现,显示类型的名称。 模板 void get(){
std::cout当对解决模板元编程问题有疑问时,考虑如何在正常编程中做到这一点是有帮助的。在这种情况下,我们需要类似以下内容:

for a in type_list:
    for b in type_list:
        foo(a,b)
class a;
class b;
class c;
template<typename A, typename B> void get() { /*....*/ }

namespace detail {
    template <typename> struct tag{};

    template <typename Tuple, std::size_t...Is>
    void get_all_pairs(tag<Tuple>, std::index_sequence<Is...>)
    {
        constexpr auto size = std::tuple_size<Tuple>::value;
#if 1 // Folding expression with C++17
        (get<std::tuple_element_t<Is / size, Tuple>,
             std::tuple_element_t<Is % size, Tuple>>(), ...);
#else
        const dummy[] = {0, (get<std::tuple_element_t<Is / size, Tuple>,
                                 std::tuple_element_t<Is % size, Tuple>>(),
                             void(), 0)...};
        static_cast<void>(dummy); // Avoid warning for unused variable.
#endif
    }

    template <typename ... Ts>
    void get_all_pairs() {
        get_all_pairs(tag<std::tuple<Ts...>>{},
                      std::make_index_sequence<sizeof...(Ts) * sizeof...(Ts)>{});
    }

}

void get_all() { detail::get_all_pairs<a, b, c>(); }
<> >,让我们直接把它翻译成C++。我们需要一种表示类型和类型的方法:

template <class T> struct tag { };
template <class... Ts> struct type_list { };
基本上就是这样。我们需要一个我们正在调用的函数,一个类型列表和代码:

template <class X, class Y>
void foo(tag<X>, tag<Y> ) {
    std::cout << __PRETTY_FUNCTION__ << '\n'; // or something more meaningful
}

int main() {
    type_list<a, b, c> types;

    for_each(types, [=](auto x){
        for_each(types, [=](auto y){
            foo(x, y);
        });});
}
请注意,我们不是返回
bool
,而是返回一个在类型系统中对结果进行编码的类型。然后我们可以自然地使用它:

for_each(types, [=](auto x){
    for_each(types, [=](auto y){
        if constexpr (x != y) {
            foo(x, y);
        }
    });});

foo(x,y)
仅在两种标记类型不同时才会被实例化。

您可以使用类似于:

for a in type_list:
    for b in type_list:
        foo(a,b)
class a;
class b;
class c;
template<typename A, typename B> void get() { /*....*/ }

namespace detail {
    template <typename> struct tag{};

    template <typename Tuple, std::size_t...Is>
    void get_all_pairs(tag<Tuple>, std::index_sequence<Is...>)
    {
        constexpr auto size = std::tuple_size<Tuple>::value;
#if 1 // Folding expression with C++17
        (get<std::tuple_element_t<Is / size, Tuple>,
             std::tuple_element_t<Is % size, Tuple>>(), ...);
#else
        const dummy[] = {0, (get<std::tuple_element_t<Is / size, Tuple>,
                                 std::tuple_element_t<Is % size, Tuple>>(),
                             void(), 0)...};
        static_cast<void>(dummy); // Avoid warning for unused variable.
#endif
    }

    template <typename ... Ts>
    void get_all_pairs() {
        get_all_pairs(tag<std::tuple<Ts...>>{},
                      std::make_index_sequence<sizeof...(Ts) * sizeof...(Ts)>{});
    }

}

void get_all() { detail::get_all_pairs<a, b, c>(); }
a类;
乙级;;
丙级;;
模板void get(){/*....*/}
名称空间详细信息{
模板结构标记{};
模板
void get_all_对(标记、标准::索引_序列)
{
constexpr auto size=std::tuple\u size::value;
#if 1//用C++17折叠表达式
(get(),…);
#否则
常量伪[]={0,(get(),
void(),0)…};
static_cast(dummy);//避免对未使用的变量发出警告。
#恩迪夫
}
模板
void get_all_pairs(){
获取所有对(标记{},
std::make_index_sequence{});
}
}
void get_all(){detail::get_all_pairs();}

如果您可以使用Boost,您可以避免许多基本的类型列表和应用程序样板文件,从而生成更易于阅读的代码。无需在此处重新发明轮子

本例使用Boost.MPL,它具有广泛的编译器支持,但我确信Boost.Hana中的等效解决方案要漂亮得多

首先,生成配对的函数(改编自):

#包括
#包括
#包括
#包括
#包括
#包括
//对于TList中的每个元素,附加到累加器
//类型对。
模板<
typename TList,typename PairFirst,typename累加器=boost::mpl::vector>
结构生成\u对\u固定\u元素:
boost::mpl::fold<
名单,
累加器,
boost::mpl::推回>
{};
//对于TList中的每个元素,连接到累加器
//生成\对\固定\元素的结果。
模板
结构生成\u对\u组合:
boost::mpl::fold<
名单,
累加器,
boost::mpl::lambda<
生成\u对\u固定\u元素
>>
{};
现在,只需将您的类型收集到一个列表中并生成组合:

class a {};
class b {};
class c {};
class d {};

typedef boost::mpl::vector<a, b, c, d> all_classes_t;

typedef generate_pairs_combinations<all_classes_t>::type all_classes_pairs_t;
a类{};
b类{};
c类{};
d类{};
typedef boost::mpl::vector所有类;
typedef生成对组合::键入所有类对;
你想对他们做什么就做什么:

#include <iostream>

#include <boost/mpl/for_each.hpp>
#include <boost/type.hpp>

template <typename A, typename B>
void get() {
    std::cout << "Getting " << typeid(A).name()
              << " and " << typeid(B).name() << std::endl;
}

struct pair_visitor {
    template <typename T, typename U>
    void operator()(boost::type<std::pair<T, U>>) const {
        get<T, U>();
    }
};

int main() {
    boost::mpl::for_each<all_classes_pairs_t, boost::type<boost::mpl::_>>(pair_visitor());
}
#包括
#包括
#包括
模板
void get(){

std::我可以写一个生成代码的脚本吗?或者研究一下设计,看看我能不能想出一些不需要我做所有这些调用的东西。也许如果你告诉我们你正试图用这样的代码解决的问题,我们也许可以帮你想出一个更好的解决方案?(,你的问题就是一个例子。)你对结果做了什么?是不是
get
真的
do\u action
?因为
get
带有
void
返回类型不是很有意义。@gmannick我怀疑
get()
有副作用,但是OP的澄清会很好。是的。get()函数实际上是一个类成员函数,它从模板对象中检索数据并存储在成员对象中。我尝试了这个方法,它似乎可以编译..直到我尝试在foo()中执行某些操作为止函数。请参见上面我的编辑:它现在抱怨
关联
是一个不完整的类型。我不知道为什么。编辑每个代码的\u并调用foo()工作正常,所以我不知道为什么。@Nathaniel我不能告诉你为什么我看不到的代码不工作。可能在某个地方定义之前,你正在使用
关联
。但是这应该允许在内部lambda体中使用任意代码-假设在那一点上所有类型都已定义。事实证明,这是一个潜在的假设,即A不是e与B相同。为了避免这种情况,重载foo()是很简单的。
#include <iostream>

#include <boost/mpl/for_each.hpp>
#include <boost/type.hpp>

template <typename A, typename B>
void get() {
    std::cout << "Getting " << typeid(A).name()
              << " and " << typeid(B).name() << std::endl;
}

struct pair_visitor {
    template <typename T, typename U>
    void operator()(boost::type<std::pair<T, U>>) const {
        get<T, U>();
    }
};

int main() {
    boost::mpl::for_each<all_classes_pairs_t, boost::type<boost::mpl::_>>(pair_visitor());
}