关于如何在使用std :: make_tuple时避免构造函数的未定义执行顺序的问题的答案导致了一个讨论,在此期间我了解到构造函数可以保证参数评估的顺序:使用braced-init-list命令保证从左到右:
T{ a, b, c }
Run Code Online (Sandbox Code Playgroud)
表达式a,b和c,按给定的顺序进行评估.即使类型T只定义了普通的构造函数,也是如此.
显然,并非所有被调用的都是构造函数,有时候在调用函数时保证求值顺序会很好,但是没有像brace-argument-list这样的东西来调用函数,并且定义了对它们的参数的评估顺序.问题变成:构造函数的保证是否可以用于构建函数调用工具(" function_apply()"),并具有用于评估参数的排序保证?要求调用函数对象是可以接受的.
Ker*_* SB 14
那个像这样的愚蠢的包装类怎么样:
struct OrderedCall
{
template <typename F, typename ...Args>
OrderedCall(F && f, Args &&... args)
{
std::forward<F>(f)(std::forward<Args>(args)...);
}
};
Run Code Online (Sandbox Code Playgroud)
用法:
void foo(int, char, bool);
OrderedCall{foo, 5, 'x', false};
Run Code Online (Sandbox Code Playgroud)
如果你想要一个返回值,你可以通过引用传递它(你需要一些特性来提取返回类型),或者将它存储在对象中,以获得如下界面:
auto x = OrderedCall{foo, 5, 'x', false}.get_result();
Run Code Online (Sandbox Code Playgroud)
我提出的解决方案std::tuple<...>用于将参数放在一起,而不是使用此对象的元素调用函数对象.优点是它可以推断出返回类型.实际的具体逻辑如下所示:
template <typename F, typename T, int... I>
auto function_apply(F&& f, T&& t, indices<I...> const*)
-> decltype(f(std::get<I>(t)...)) {
f(std::get<I>(t)...);
}
template <typename F, typename T>
auto function_apply(F&& f, T&& t)
-> decltype(function_apply(std::forward<F>(f), std::forward<T>(t),
make_indices<T>())) {
function_apply(std::forward<F>(f), std::forward<T>(t),
make_indices<T>());
}
Run Code Online (Sandbox Code Playgroud)
...使用这样的表达式调用:
void f(int i, double d, bool b) {
std::cout << "i=" << i << " d=" << d << " b=" << b << '\n';
}
int fi() { std::cout << "int\n"; return 1; }
double fd() { std::cout << "double\n"; return 2.1; }
bool fb() { std::cout << "bool\n"; return true; }
int main()
{
std::cout << std::boolalpha;
function_apply(&f, std::tuple<int, double, bool>{ fi(), fd(), fb() });
}
Run Code Online (Sandbox Code Playgroud)
主要缺点是这种方法需要规范std::tuple<...>元素.另一个问题是MacOS上当前版本的gcc以与它们出现的相反顺序调用函数,即,不遵循braced-init-list中的评估顺序(gcc bug)或不存在(即,我误解了使用braced-init-list的保证.同一平台上的clang以预期的顺序执行函数.
used函数make_indices()只是创建一个指向类型对象的合适指针,indices<I...>其中索引列表可用于std::tuple<...>:
template <int... Indices> struct indices;
template <> struct indices<-1> { typedef indices<> type; };
template <int... Indices>
struct indices<0, Indices...>
{
typedef indices<0, Indices...> type;
};
template <int Index, int... Indices>
struct indices<Index, Indices...>
{
typedef typename indices<Index - 1, Index, Indices...>::type type;
};
template <typename T>
typename indices<std::tuple_size<T>::value - 1>::type const*
make_indices()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1894 次 |
| 最近记录: |