大家7月4日快乐!好的,给你。
事实证明,g++-4.7
在 iniling 方面非常棒,并根据我的测试创建了相同的机器代码(重现结果的说明在代码下方)。
#include <iostream>
#include <tuple>
#include <typeinfo>
#include <type_traits>
template <class... Args>
struct sequence
{
typedef std::tuple<Args...> tuple_type;
};
template <class U, class V>
struct sequence_cat;
template <class... U, class... V>
struct sequence_cat<sequence<U...>, sequence<V...>>
{
typedef sequence<U..., V...> type;
};
template <class... V>
struct sequence_cat<void, sequence<V...>>
{
typedef sequence<V...> type;
};
template <class... U>
struct sequence_cat<sequence<U...>, void>
{
typedef sequence<U...> type;
};
template <>
struct sequence_cat<void, void>
{
typedef void type;
};
template <class T>
struct undecorate
{
typedef typename std::remove_reference<T>::type noref_type;
typedef typename std::remove_pointer<noref_type>::type noptr_type;
typedef typename std::remove_cv<noptr_type>::type type;
};
template <class T>
struct deduce_storage_type
{
typedef T type;
};
template <class T>
struct deduce_storage_type<T&>
{
typedef T* type;
};
template <class T>
struct deduce_storage_type<const T&>
{
typedef T type;
};
template <class T>
struct deduce_storage_type<T&&>
{
typedef T type;
};
template <class T, class... Args>
struct filter_type;
template <class T, class Arg, class... Args>
struct filter_type<T, Arg, Args...>
{
static constexpr bool pred =
std::is_same<typename undecorate<Arg>::type, T>::value;
typedef typename deduce_storage_type<Arg>::type storage_type;
typedef typename
std::conditional<
pred,
typename sequence_cat<
sequence<storage_type>,
typename filter_type<T, Args...>::type
>::type,
typename filter_type<T, Args...>::type
>::type type;
};
template <class T, class Arg>
struct filter_type<T, Arg>
{
static constexpr bool pred =
std::is_same<typename undecorate<Arg>::type, T>::value;
typedef typename deduce_storage_type<Arg>::type storage_type;
typedef typename
std::conditional<pred, sequence<storage_type>, void>::type
type;
};
template <class... Args>
struct deduce_sequence_type
{
typedef typename filter_type<char, Args...>::type char_sequence;
typedef typename filter_type<int, Args...>::type int_sequence;
typedef typename filter_type<float, Args...>::type float_sequence;
typedef typename
sequence_cat<
char_sequence,
typename sequence_cat<
int_sequence,
float_sequence
>::type
>::type type;
};
template <class T>
struct get_storage_type
{
static T apply(T t) { return t; }
};
template <class T>
struct get_storage_type<T&>
{
static T* apply(T& t) { return &t; }
};
template <class T>
struct get_storage_type<const T&>
{
static T apply(const T& t) { return t; }
};
template <class T>
struct get_storage_type<T&&>
{
static T&& apply(T&& t) { return std::move(t); }
};
template <class T, class Arg>
struct equals_undecorated_type
{
static constexpr bool value =
std::is_same<typename undecorate<Arg>::type, T>::value;
};
template <bool Pred, bool IsNextVoid, class T, class... Args>
struct filter_parameter_impl;
template <class T, class Arg1, class Arg2, class... Args>
struct filter_parameter_impl<false, false, T, Arg1, Arg2, Args...>
{
typedef typename filter_type<T, Arg2, Args...>::type sequence_type;
typedef typename sequence_type::tuple_type tuple_type;
static constexpr bool pred = equals_undecorated_type<T, Arg2>::value;
static constexpr bool is_next_next_void =
std::is_same<typename filter_type<T, Args...>::type, void>::value;
static tuple_type apply(Arg1&&, Arg2&& arg2, Args&&... args)
{
return filter_parameter_impl<
pred, is_next_next_void, T, Arg2, Args...
>::apply(
std::forward<Arg2>(arg2),
std::forward<Args>(args)...
);
}
};
template <class T, class Arg1, class Arg2, class... Args>
struct filter_parameter_impl<false, true, T, Arg1, Arg2, Args...>
{
static void apply(Arg1&&, Arg2&&, Args&&...) {}
};
template <class T, class Arg1, class Arg2, class... Args>
struct filter_parameter_impl<true, false, T, Arg1, Arg2, Args...>
{
typedef typename
filter_type<T, Arg1, Arg2, Args...>::type
sequence_type;
typedef typename sequence_type::tuple_type tuple_type;
static constexpr bool pred = equals_undecorated_type<T, Arg2>::value;
static constexpr bool is_next_next_void =
std::is_same<typename filter_type<T, Args...>::type, void>::value;
static tuple_type apply(Arg1&& arg1, Arg2&& arg2, Args&&... args)
{
return std::tuple_cat(
std::make_tuple(get_storage_type<Arg1>::apply(arg1)),
filter_parameter_impl<
pred, is_next_next_void, T, Arg2, Args...
>::apply(
std::forward<Arg2>(arg2),
std::forward<Args>(args)...
)
);
}
};
template <class T, class Arg1, class Arg2, class... Args>
struct filter_parameter_impl<true, true, T, Arg1, Arg2, Args...>
{
typedef typename filter_type<T, Arg1>::type sequence_type;
typedef typename sequence_type::tuple_type tuple_type;
static tuple_type apply(Arg1&& arg1, Arg2&&, Args&&...)
{
return std::make_tuple(get_storage_type<Arg1>::apply(
std::forward<Arg1>(arg1)
));
}
};
template <class T, class Arg1, class Arg2>
struct filter_parameter_impl<false, false, T, Arg1, Arg2>
{
typedef typename filter_type<T, Arg2>::type sequence_type;
typedef typename sequence_type::tuple_type tuple_type;
static tuple_type apply(Arg1&&, Arg2&& arg2)
{
return std::make_tuple(get_storage_type<Arg2>::apply(
std::forward<Arg2>(arg2)
));
}
};
template <class T, class Arg1, class Arg2>
struct filter_parameter_impl<false, true, T, Arg1, Arg2>
{
static void apply(Arg1&&, Arg2&&) {}
};
template <class T, class Arg1, class Arg2>
struct filter_parameter_impl<true, false, T, Arg1, Arg2>
{
typedef typename filter_type<T, Arg1>::type sequence_type;
typedef typename sequence_type::tuple_type tuple_type;
static tuple_type apply(Arg1&& arg1, Arg2&& arg2)
{
return std::make_tuple(
get_storage_type<Arg1>::apply(std::forward<Arg1>(arg1)),
get_storage_type<Arg2>::apply(std::forward<Arg2>(arg2))
);
}
};
template <class T, class Arg1, class Arg2>
struct filter_parameter_impl<true, true, T, Arg1, Arg2>
{
typedef typename filter_type<T, Arg1, Arg2>::type sequence_type;
typedef typename sequence_type::tuple_type tuple_type;
static tuple_type apply(Arg1&& arg1, Arg2&&)
{
return std::make_tuple(
get_storage_type<Arg1>::apply(std::forward<Arg1>(arg1))
);
}
};
template <class T, class... Args>
struct filter_parameter;
template <class T, class Arg, class... Args>
struct filter_parameter<T, Arg, Args...>
{
typedef typename filter_type<T, Arg, Args...>::type sequence_type;
typedef typename std::conditional<
std::is_same<sequence_type, void>::value,
void,
typename sequence_type::tuple_type
>::type tuple_type;
static constexpr bool pred = equals_undecorated_type<T, Arg>::value;
static constexpr bool is_next_void =
std::is_same<typename filter_type<T, Args...>::type, void>::value;
static tuple_type apply(Arg&& arg, Args&&... args)
{
return filter_parameter_impl<
pred, is_next_void, T, Arg, Args...
>::apply(std::forward<Arg>(arg), std::forward<Args>(args)...);
}
};
template <bool Is1Void, bool Is2Void, bool Is3Void, class... Args>
struct get_tuple_impl;
template <class... Args>
struct get_tuple_impl<false, false, false, Args...>
{
typedef typename deduce_sequence_type<Args...>::type sequence_type;
typedef typename sequence_type::tuple_type tuple_type;
static tuple_type apply(Args&&... args)
{
return std::tuple_cat(
filter_parameter<char, Args...>::apply(
std::forward<Args>(args)...
),
filter_parameter<int, Args...>::apply(
std::forward<Args>(args)...
),
filter_parameter<float, Args...>::apply(
std::forward<Args>(args)...
)
);
}
};
template <class... Args>
struct get_tuple
{
typedef typename deduce_sequence_type<Args...>::type sequence_type;
typedef typename std::conditional<
std::is_same<sequence_type, void>::value,
void,
typename sequence_type::tuple_type
>::type tuple_type;
static constexpr bool is1void =
std::is_same<typename filter_type<char, Args...>::type, void>::value;
static constexpr bool is2void =
std::is_same<typename filter_type<int, Args...>::type, void>::value;
static constexpr bool is3void =
std::is_same<typename filter_type<float, Args...>::type, void>::value;
static tuple_type apply(Args&&... args)
{
return get_tuple_impl<is1void, is2void, is3void, Args...>::
apply(std::forward<Args>(args)...);
}
};
template <class... Args>
struct foo
{
typedef typename deduce_sequence_type<Args...>::type sequence_type;
typedef typename sequence_type::tuple_type tuple_type;
tuple_type t_;
foo(Args&&... args) : t_{} {}
};
int main()
{
char a = 5;
const int b = 6;
float c = 7;
int d = 8;
float e = 9;
char f = 10;
auto x = get_tuple<char&, const int&, float&, int&, float&&, char&>::
apply(a, b, c, d, std::move(e), f);
//std::tuple<char*, char*, int, int*, float*, float> x{&a, &f, b, &d, &c, std::move(f)};
std::cout << typeid(x).name() << std::endl;
return 0;
}
为了重现结果,请执行以下操作(假设您已安装 g++-4.7)。
g++ -std=c++11 -Wall -Ofast -march=native variadic_reorder.cpp -S -o with_templates.s
// Comment out the line in main, and comment the line containing auto x, as well as the line below it.
g++ -std=c++11 -Wall -Ofast -march=native variadic_reorder.cpp -S -o without_templates.s
vimdiff with_templates.s without_templates.s
我注意到的唯一区别是标签名称之类的东西。否则,生成的机器代码是相同的。
编辑 1
我将接受我自己的答案,直到其他人发布比我所拥有的更优雅的东西。