How to guarantee order of argument evaluation when calling a function object?

前端 未结 4 1743
深忆病人
深忆病人 2020-11-27 16:41

The answers to the question on how to avoid undefined execution order for the constructors when using std::make_tuple led to a discussion during which I learned that the ord

4条回答
  •  天涯浪人
    2020-11-27 17:14

    The solution I had come up uses std::tuple<...> to put the arguments together than calls a function object using the elements of this object. The advantage is that it can deduce the return type. The actual specific logic looks like this:

    template 
    auto function_apply(F&& f, T&& t, indices const*)
        -> decltype(f(std::get(t)...)) {
        f(std::get(t)...);
    }
    
    template 
    auto function_apply(F&& f, T&& t)
        -> decltype(function_apply(std::forward(f), std::forward(t),
                                   make_indices())) {
        function_apply(std::forward(f), std::forward(t),
                       make_indices());
    }
    

    ... which is called using an expression like this:

    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{ fi(), fd(), fb() });
    }
    

    The main disadvantage is that this approach requires the specification of the std::tuple<...>'s elements. Another problem is that the current version of gcc on MacOS calls the functions in the opposite order they appear, i.e., the order of evaluation in a braced-init-list isn't obeyed (a gcc bug) or doesn't exist (i.e., I misunderstood the guarantees of using a braced-init-list. clang on the same platform executes the functions in the expected order.

    The used function make_indices() just creates a suitable pointer to an object of type indices with a list of indices usable with a std::tuple<...>:

    template  struct indices;
    template <> struct indices<-1> { typedef indices<> type; };
    template 
    struct indices<0, Indices...>
    {
        typedef indices<0, Indices...> type;
    };
    template 
    struct indices
    {
        typedef typename indices::type type;
    };
    
    template 
    typename indices::value - 1>::type const*
    make_indices()
    {
        return 0;
    }
    

提交回复
热议问题