2

所以我有以下情况,为长示例道歉,但它应该正确编译:

#include <tuple>
#include <functional>
#include <iostream>

#include <boost/mpl/fold.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/vector.hpp>


namespace mpl = boost::mpl;

namespace aux
{
template <typename ...Args>
struct to_vector
{ };

template <typename T, typename ...Args>
struct to_vector<T, Args...>
{ typedef typename mpl::push_front<typename to_vector<Args...>::type, T>::type type; };

template <typename T>
struct to_vector<T>
{ typedef typename mpl::vector<T> type; };

template <>
struct to_vector<>
{ typedef typename mpl::vector<> type; };

template <typename Dest, typename T>
struct tuple_adder
{
  typedef decltype(std::tuple_cat(std::declval<Dest>(), std::make_tuple(std::declval<T>()))) type;
};

}

struct foo
{
  struct storage
  { };

  template <typename T>
  struct placeholder : storage
  {
    placeholder(T&& t) : content(t)
    { }

    T content;
  };

  storage* data;


  template <typename ...Args>
  foo(Args&&... args)
  : data()
  {
    typedef typename mpl::fold<
      typename aux::to_vector<Args...>::type,
      std::tuple<>,
      aux::tuple_adder<mpl::_1, mpl::_2>
    >::type tuple_type;
    // Instantiate the tuple
    data = new placeholder<tuple_type>(std::make_tuple(std::forward<Args>(args)...));
  }

  template <typename ...Args>
  void set(Args&&... args)
  {
    typedef typename mpl::fold<
      typename aux::to_vector<Args...>::type,
      std::tuple<>,
      aux::tuple_adder<mpl::_1, mpl::_2>
    >::type tuple_type;

    auto tp = static_cast<placeholder<tuple_type>*>(data);
    *tp = std::make_tuple(std::forward<Args>(args)...);
  }
};


int main()
{
  foo f(1, 2., std::string("Hello"));

  f.set(4, 3., std::string("Bar"));

  f.set(3., std::string("Bar"), 3.);
}

这个想法很简单,foo利用类型擦除来存储tuple通过构造函数构造的 a。那么限制应该set是只有在从可变参数列表生成的与持有的元组匹配的情况下才允许tuple(不幸的是,它的类型已被删除。)

现在我可以在运行时使用 来检测这一点typeid(),但是,我想知道是否有一种方法可以在编译时进行相同的检测。唯一的限制是foo不能被模板化,并且variant因为我想允许foo在必要时使用字段构造(所有在编译时指定......)

我担心答案是这是不可能的(由于类型擦除),但是我希望有一些想法来实现这个功能......

4

1 回答 1

3

编译时类型系统的要点在于它限制了对类型值的允许操作。如果两个对象是同一类型,则它们承认相同的允许操作。

所以不,编译器无法知道你想要允许什么,因为你已经消除了区别。

于 2013-03-01T12:00:04.680 回答