是否可以在编译时检测以下赋值?

时间:2013-03-01 11:57:07

标签: c++ templates c++11

所以我有以下案例,对长篇例子道歉,但它应该正确编译:

#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。然后限制应该是set只允许从变量参数列表生成的tuple与保持的元组匹配(不幸的是它的类型已被删除)。

现在我可以使用typeid()在运行时检测到这一点,但是,我想知道是否有一种方法可以在编译时进行相同的检测。唯一的限制是foo无法模板化,variant已经出局,因为我希望允许foo根据需要构造字段(所有在编译时指定...)

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

1 个答案:

答案 0 :(得分:3)

编译时类型系统的要点是它约束了类型值的允许操作。如果两个对象的类型相同,那么他们会接受相同的允许操作。

所以不,鉴于您已经删除了区别,编译器无法知道您想要允许的内容。