如果编译器不支持,可以将可变参数传递给lambda表达式
Workaround for passing variadic arguments to lambda expression if compiler does not support it
我有两个解决方案,都像我期望的那样工作,但第一个仅适用于较新版本的GCC(肯定是5.2.1),第二个适用于GCC>= 4.8.3。问题是,不幸的是,在我的工作中,我没有访问新版本的GCC。
第一个解决方案基本上是我想要的行为和复杂程度。第二个也可以工作,但这是我写过的最丑陋的东西,老实说,我不知道这是不是正确的代码(但它可以工作)。
好的,首先我将描述我所面临的问题:这里有一个叫做logic()
的函数,它接受一个可调用对象来调用其他指令中的一些附加逻辑。这些说明当然不在这里,因为它们是不必要的,它们被标记为(X)
。
template <typename C>
void logic (C c) {
// before callable actions (X)
c ();
// after callable actions (X)
}
作为可调用对象,我想做的是使用适当的类型(s) - set_single()
函数设置一些bool
值。对于这个例子,我将使用一些额外的类型:
struct P1 {};
struct P2 {};
struct P3 {};
考虑第一个解决方案:
namespace Solution1 {
template <typename T>
void set_single (bool c) {
// use type T to set c value - details are not the case here.
std::cout << "value = " << c << std::endl;
std::cout << "P1 = " << std::is_same<T, P1>::value << std::endl;
std::cout << "P2 = " << std::is_same<T, P2>::value << std::endl;
std::cout << "P3 = " << std::is_same<T, P3>::value << std::endl;
}
template <typename T, typename K, typename... Ts, typename... Vs>
void set_single (bool t, bool k, Vs&&... args) {
set_single<T> (t);
set_single<K, Ts...> (k, std::forward<Vs> (args)...);
}
template <typename... Ts, typename... Args>
void set (Args&&... args) {
static_assert (sizeof... (Ts) == sizeof... (Args), "");
logic ([&] () {
set_single<Ts...> (std::forward<Args> (args)...);
});
}
}
set()
函数是一个包装器,它对用户是公共的,set_single()
是实现细节,所以它们是隐藏的(为了简单起见,它们不是写在类中)。
因此,将可调用对象传递给set()
函数中的logic()
函数,我调用set_single()
函数任意次数,传递我需要的具有相应类型的所有值。因此,例如,用法可以像这样:
Solution1::set<P1, P2, P3> (true, false, true);
,这将使用类型P1
设置为true,类型P2
设置为false,类型P3
设置为true。
所以,当你的编译器不支持向lambda表达式传递可变参数时,我们有了一个解决方案。
namespace Solution2 {
template <typename... Ts>
struct X {
X () = default;
X (Ts... t) : tup {std::make_tuple (t...)} {}
std::tuple<Ts...> tup;
};
template <int...>
struct Ints {};
template <int N, int... Is>
struct Int_seq : Int_seq<N-1, N, Is...> {};
template <int... Is>
struct Int_seq<0, Is...> {
using type = Ints<0, Is...>;
};
template <int... Is>
using Iseq = typename Int_seq<Is...>::type;
template <int I, typename... Args, typename... Types>
void set_single (Ints<I>, const std::tuple<Args...>& a, const std::tuple<Types...>& t) {
std::cout << "value = " << std::get<I> (a) << std::endl;
auto p1 = std::get<I> (t);
auto p2 = std::get<I> (t);
auto p3 = std::get<I> (t);
std::cout << "P1 = " << std::is_same<P1, decltype (p1)>::value << std::endl;
std::cout << "P2 = " << std::is_same<P2, decltype (p2)>::value << std::endl;
std::cout << "P3 = " << std::is_same<P3, decltype (p3)>::value << std::endl;
}
template <int I, int K, int... Is, typename... Args, typename... Types>
void set_single (Ints<I, K, Is...>, const std::tuple<Args...>& a, const std::tuple<Types...>& t) {
set_single (Ints<I> {}, a, t);
set_single (Ints<K, Is...> {}, a, t);
}
template <typename... Ts, typename... Args>
void set (Args... args) {
static_assert (sizeof... (Ts) == sizeof... (Args), "");
X<Ts...> types {};
X<Args...> arguments {args...};
logic ([&types, &arguments] () {
set_single (Iseq<std::tuple_size<decltype (arguments.tup)>::value-1> {}, arguments.tup, types.tup);
});
}
}
我使用类型Solution2::X
来存储值和类型。我试着做一些std::bind()
的东西,但它是痛苦的,所以我使用一些整数序列(可能实现得很差)。就像我说的,两种解决方案都有效,但第二个解决方案没有第一个那么酷。
你们谁能告诉我Solution2
是否可以被某种更简单的解决方案取代?
和输出的用法如下:
Solution1::set<P1, P2, P3> (true, false, true);
value = 1
P1 = 1
P2 = 0
P3 = 0
value = 0
P1 = 0
P2 = 1
P3 = 0
value = 1
P1 = 0
P2 = 0
P3 = 1
Solution2::set<P1, P2, P3> (true, false, true);
value = 1
P1 = 1
P2 = 0
P3 = 0
value = 0
P1 = 0
P2 = 1
P3 = 0
value = 1
P1 = 0
P2 = 0
P3 = 1
您需要使用一些标记来保持给定的类型,因为它们可能不是默认可构造的。
我将这样实现:
#if 1 // Not in C++11 // make_index_sequence
#include <cstdint>
template <std::size_t...> struct index_sequence {};
template <std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
template <std::size_t... Is>
struct make_index_sequence<0u, Is...> : index_sequence<Is...> {};
#endif // make_index_sequence
#if 1 // Not in C++11 // tuple_element_t
template <std::size_t I, typename T>
using tuple_element_t = typename std::tuple_element<I, T>::type;
#endif
namespace Solution3 {
template <typename T>
struct bool_impl {
using type = bool;
};
template <typename T>
using bool_t = typename bool_impl<T>::type; // or simply using bool_t = bool
template <typename T>
void set_single (bool c) {
// use type T to set c value - details are not the case here.
std::cout << "value = " << c << std::endl;
std::cout << "P1 = " << std::is_same<T, P1>::value << std::endl;
std::cout << "P2 = " << std::is_same<T, P2>::value << std::endl;
std::cout << "P3 = " << std::is_same<T, P3>::value << std::endl;
}
template <typename T> struct Tag {};
template <typename T1, typename T2, std::size_t ... Is>
void set_singles (Tag<T1>, T2 t, index_sequence<Is...>) {
int dummy[] = {0, (set_single<tuple_element_t<Is, T1>>(std::get<Is>(t)), 0)...};
static_cast<void>(dummy); // Avoid warning for unused variable
}
template <typename... Ts>
void set (bool_t<Ts>... args) {
Tag<std::tuple<Ts...>> tag;
auto bools = std::make_tuple(args...);
auto seq = make_index_sequence<sizeof...(Ts)>();
logic ([&]() {
set_singles(tag, bools, seq);
});
}
}
演示和为最新编译器简化的版本
演示- 将__device__ lambda 作为参数传递给 __global__ 函数
- 将 lambda 函数作为参数传递C++
- 将参数传递给泛型 lambda 时复制构造函数不正确
- 通过参数传递 lambda(无函数类型模板)
- 在C++ Lambda 表达式中,为什么人们更喜欢按值捕获而不是作为参数传递?
- 是否可以将带有捕获和参数的 lambda 传递给另一个函数?如果是这样,如何?
- Lambda闭包左值可以作为右值参考参数传递
- 在C++17中,lambda是否可以作为模板参数传递
- 如何在C++中将 lambda 表达式作为参数传递
- 如何将 lambda 表达式作为参数传递到可变参数模板类中的 mermber 函数中
- 将带有自动参数的 lambda 传递给另一个函数是否合法
- 将函数的引用和 lambda 表达式作为参数传递时有什么区别?
- 为什么在传递lambda而不是功能指针时不能推断模板参数
- 将 lambda 作为参数传递时的重载函数
- 如何在C++中使用单个模板参数传递两个 lambda 函数
- 将 lambda 作为模板参数传递:实际推导出什么类型
- c++:将带有参数的lambda传递给函数
- 调用从 lambda 作为模板参数传递的成员函数指针会崩溃
- C++将Lambda函数作为类构造函数参数传递
- 如何通过boost::函数参数传递lambda到被覆盖的方法