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...>