したがって、次のケースがあります。長い例で申し訳ありませんが、正しくコンパイルする必要があります。
#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
(すべてコンパイル時に指定されます...)
答えは、これは不可能であるということです(型消去のため)が、この機能を実現する方法のいくつかのアイデアを望んでいます...