C++ 元编程和SFINAE/std::enable_if:无限模板递归

C++ 元编程和SFINAE/std::enable_if:无限模板递归,c++,c++11,metaprogramming,template-meta-programming,sfinae,C++,C++11,Metaprogramming,Template Meta Programming,Sfinae,考虑以下计划: // Include #include <iostream> #include <type_traits> #include <utility> #include <tuple> #include <string> // Base class template <class Crtp, class... Types> struct Base { // Constructor calling the

考虑以下计划:

// Include
#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>
#include <string>

// Base class
template <class Crtp, class... Types>
struct Base
{
    // Constructor calling the transmute function
    template <class... OtherTypes> 
    explicit inline Base(const OtherTypes&... source) 
    : _data(transmute<std::tuple<Types...>>(std::forward_as_tuple(source...))) 
    {;}

    // Transmute: create a new object
    template <class Output> 
    static constexpr Output transmute() 
    {return Output();}

    // Transmute: forward existing object
    template <class Output, 
              class Input, 
              class = typename std::enable_if<
                          std::is_convertible<
                              typename std::remove_cv<typename std::remove_reference<Input>::type>::type, 
                              typename std::remove_cv<typename std::remove_reference<Output>::type>::type
                          >::value
                      >::type> 
    static constexpr Input transmute(Input&& input) 
    {return std::forward<Input>(input);} 

    // Transmute: recursive transmutation
    template <class Output, 
              class... Input, 
              class = typename std::enable_if<
                          (sizeof...(Input) <= std::tuple_size<Output>::value) 
                          && (sizeof...(Input) != std::tuple_size<Output>::value)
                      >::type>
    static constexpr Output transmute(const Input&... input) 
    {return transmute<Output>(input..., typename std::tuple_element<sizeof...(Input), Output>::type());}

    // Transmute: final step
    template <class Output, 
              class... Input, 
              class = typename std::enable_if<
                          (sizeof...(Input) == std::tuple_size<Output>::value) 
                          && (sizeof...(Input) != 0)
                      >::type> 
    static constexpr Output transmute(Input&&... input) 
    {return transmute<Output>(std::forward_as_tuple(std::forward<Input>(input)...));}

    // Data member
    std::tuple<Types...> _data; 
};

// Derived class
struct Derived
: public Base<Derived, std::string, bool>
{
    // Universal reference constructor
    template <class... Misc> 
    explicit inline Derived(Misc&&... misc) 
    : Base<Derived, std::string, bool>(std::forward<Misc>(misc)...) 
    {;}
};

// Main
int main(int argc, char* argv[])
{
    Derived a("hello"); // Boom !!!!
    return 0;
}
//包括
#包括
#包括
#包括
#包括
#包括
//基类
模板
结构基
{
//调用transmute函数的构造函数
模板
显式内联基(const OtherTypes&…source)
:_数据(转换(标准::转发作为元组(源…)
{;}
//转化:创建一个新对象
模板
静态constexpr输出转换()
{返回输出();}
//转化:向前移动现有对象
模板::值
>::类型>
静态constexpr输入转换(输入和输入)
{return std::forward(输入);}
//蜕变:递归蜕变
模板
静态常量表达式输出转换(常量输入和…输入)
{return transmute(input…,typename std::tuple_element::type());}
//蜕变:最后一步
模板::类型>
静态constexpr输出转换(输入和…输入)
{return transmute(std::forward_as_tuple(std::forward(input)…);}
//数据成员
std::tuple\u数据;
};
//派生类
结构派生
:公共基地
{
//通用引用构造函数
模板
显式内联派生(杂项和…杂项)
:基本(标准::正向(杂项)…)
{;}
};
//主要
int main(int argc,char*argv[])
{
派生出一个(“你好”);//轰!!!!
返回0;
}
如果您试图编译它,编译器将“爆炸”,抛出一个相当令人印象深刻的错误与模板的模板的模板的模板


我的问题很简单:问题在哪里?如何解决它?

如果我正确理解了你的意图,看起来你想要的是将
M
参数传递给一个
std::tuple
大小
N
,其中
M如果我正确理解了你的意图,看起来您想要的是将
M
参数传递给大小为
N
std::tuple
,其中
M类似于呈现整个程序和输入,并在运行时说它“崩溃”。出了什么问题?少做点事。测试每个组件。找到从测试和工作到测试和失败的变化。包括关于您尝试做什么的丰富文档。尽量简化并以较少的粗枝大叶产生相同的错误。
(sizeof…(输入)
:_数据(transmute(source…)
,并进行编译(删除
std::forward_as_tuple
).但不确定是否正确。但就我所了解的元编程而言,作为元组转发是不正确的:最后一步要求所有参数不要包装在元组中;在当前代码中,
std::tuple
是根据
“hello”创建的
无法转换为
std::string
,因此转发从未发生过。+1,我刚刚发现这是错误的根源,就像3分钟前一样。只需接受mpark。编写重复答案没有任何好处。因此,这类似于提出整个程序和输入,并说它“在运行时崩溃。出了什么问题?”做得更少事情。测试每个组件。找到从测试和工作到测试和失败的变化。包括大量关于您尝试执行的操作的文档。尝试简化并以更少的粗糙度产生相同的错误。
(sizeof…(Input)
:\u数据(transmute(source…)
,它会编译(删除了
std::forward\u as_tuple
)。但不确定它是否正确。但据我所知,元编程中的“forward as tuple”是不正确的:最后一步要求所有参数不要包装在一个tuple中;在当前代码中,
std::tuple
是根据
“hello”创建的
无法转换为
std::string
,因此转发从未发生过。+1,我刚刚发现这是错误的根源,就像3分钟前一样。只需接受mpark。编写重复答案没有任何好处。
template <class... OtherTypes>
explicit inline Base(const OtherTypes&... source)
: _data(transmute<std::tuple<Types...>>(source...))
{;}
template <typename T, typename Seq, T Begin>
struct make_integer_range_impl;

template <typename T, T... Ints, T Begin>
struct make_integer_range_impl<T, std::integer_sequence<T, Ints...>, Begin>
    : public std::common_type<std::integer_sequence<T, Begin + Ints...>> {};

/* Similar to std::make_integer_sequence<>, except it goes from [Begin, End)
   instead of [0, Size). */
template <typename T, T Begin, T End>
using make_integer_range = typename make_integer_range_impl<
    T, std::make_integer_sequence<T, End - Begin>, Begin>::type;

/* Similar to std::make_index_sequence<>, except it goes from [Begin, End)
   instead of [0, Size). */
template <std::size_t Begin, std::size_t End>
using make_index_range = make_integer_range<std::size_t, Begin, End>;

/* Trivial wrapper for std::tuple_element<>. */
template <std::size_t Idx, typename Tuple>
using tuple_element_t = typename std::tuple_element<Idx, Tuple>::type;

template <typename... Args>
class Partial {
  public:

  /* Our tuple type. */
  using Tuple = std::tuple<Args...>;

  /* Create an index_range, [# of arguments, tuple size),
     and forward the arguments to the delegating constructor. */
  template <typename... ForwardArgs>
  Partial(ForwardArgs &&... forward_args)
      : Partial(make_index_range<sizeof...(ForwardArgs),
                                 std::tuple_size<Tuple>::value>(),
                std::forward<ForwardArgs>(forward_args)...) {}

  private:

  /* The given indices are for the missing arguments, get the corresponding
     types out of the tuple and default construct them. */
  template <std::size_t... Indices, typename... ForwardArgs>
  Partial(std::index_sequence<Indices...> &&, ForwardArgs &&... forward_args)
      : tuple_{std::forward<ForwardArgs>(forward_args)...,
               tuple_element_t<Indices, Tuple>{}...} {}

  /* Our tuple instance. */
  Tuple tuple_;

};  // Partial<Args...>