在运行时期间获取元组中索引的类型

时间:2013-12-14 20:45:27

标签: c++ c++11 tuples template-meta-programming

我知道,有几个主题,要求非常接近的事情,但我不能让它在我的情况下工作。

我想在运行时期间构建一个具有索引访问权限的模板化工厂。因此我有几种类型相同的基类型。工厂获取每个模板参数能够获取的类型。对工厂的调用只给出一个索引。这是一个小例子:

#include <iostream>
#include <memory>
#include <tuple>

struct Base {
};

struct A : Base {
  A(int) { std::cout << "A" << std::endl; }
};
struct B : Base {
  B(int) { std::cout << "B" << std::endl; }
};
struct C : Base {
  C(int) { std::cout << "C" << std::endl; }
};

template <typename ... Types>
struct Factory {
  typedef std::tuple<Types...> TypesTuple;

  std::shared_ptr<Base> operator ()(int index) {
    return produce(index);
  }

  std::shared_ptr<Base> produce(int index) {
    switch (index) {
    case 0: return std::make_shared<typename std::tuple_element<0, TypesTuple>::type>(42);
    case 1: return std::make_shared<typename std::tuple_element<1, TypesTuple>::type>(42);
    }
    throw; 
  }
};

//==============================================================================
int main() {    
  Factory<A, C> factory_ac;
  auto a1 = factory_ac(0);
  auto c1 = factory_ac(1);

  Factory<A, B, C> factory_bc;
  auto a2 = factory_bc(0);
  auto b2 = factory_bc(1);
  auto c2 = factory_bc(2);
}

我尝试用

重载了crop方法
template <typename = typename std::enable_if<std::tuple_size<TypesTuple>::value==2>::type>

计算大小并提供相应的switch语句,但这不会编译,不允许超载。

我尝试使用https://stackoverflow.com/a/7383493/2524462但我无法使其工作,因为参数包不会扩展为lambda并将其包装在模板函数中我遇到了constexpr数组的问题因为我没有琐碎的类型。

Boost MPL for_each浮现在脑海中,但我遇到了编译问题,因为我的类型不是简单的构造。

那么如何更改工厂以使主要编译和工作?

2 个答案:

答案 0 :(得分:4)

这似乎可以很直接地完成:

template <typename T>
std::shared_ptr<Base> make() {
    return std::make_shared<T>();
}
template <typename... T>
class Factory {
public:
    std::shared_ptr<Base> operator()(int index) {
        static constexpr std::shared_ptr<Base> (*factories[])() = {
            &make<T>...
        };
        if (index < 0 && sizeof...(T) <= index) {
            throw std::range_error("type index out of range");
        }
        return (factories[index])();
    }
};

我目前无法编译代码,但是这一行应该有效:想法是创建一个工厂函数数组,然后调用这个数组。

答案 1 :(得分:1)

如果我已正确理解您的要求,我认为这样做符合您的要求:

template<int... Is>
struct indices { typedef indices type; };

template<int N, int... Is>
struct make_indices : make_indices<N - 1, N - 1, Is...> { };

template<int... Is>
struct make_indices<0, Is...> : indices<Is...> { };

template<typename... Types>
struct Factory
{
    typedef std::tuple<Types...> TypesTuple;

    std::shared_ptr<Base> operator()(int const index)
    {
        return produce(index);
    }

    std::shared_ptr<Base> produce(int const index)
    {
        return produce_impl(make_indices<sizeof...(Types)>(), index);
    }

    template<int I, int... Is>
    std::shared_ptr<Base> produce_impl(indices<I, Is...>, int const index)
    {
        if (I == index) {
            return std::make_shared<typename std::tuple_element<I, TypesTuple>::type>(42);
        }

        return produce_impl(indices<Is...>(), index);
    }

    std::shared_ptr<Base> produce_impl(indices<>, int const index)
    {
        throw "Uh-oh!";
    }
};

请参阅输出here