Access function's parameter by argument position



  • Hello,

    What I mean if the title is confusing:

    void foo(_x,_y,_z)
    {
    x = param_list[0]; //x=_x
    y = param_list[1]; //y=_y
    z = param_list[2]; //z=_z
    }
    instead of:

    void foo(_x,_y,_z)
    {
    x = _x
    y = _y
    z = _z
    }



  • @Ahzmandius a few approaches to this problem could be:

    #include <utility>
    #include <tuple>
    #include <array>
    #include <iostream>
    
    struct A
    {
        void f1(int x_, int y_, int z_)
        {
            auto param_list = std::tuple<int, int, int>{ x_, y_, z_ };
            x = std::get<0>(param_list);
            y = std::get<1>(param_list);
            z = std::get<2>(param_list);
        }
    
        void f2(int x_, int y_, int z_)
        {
            auto param_list = std::array<int, 3>{ x_, y_, z_ };
            x = param_list[0];
            y = param_list[1];
            z = param_list[2];
        }
    
        template <typename... Ts>
        void f3(Ts&&... args)
        {
            auto param_list = std::tuple<Ts...>{ std::forward<Ts>(args)... };
            x = std::get<0>(param_list);
            y = std::get<1>(param_list);
            z = std::get<2>(param_list);
        }
    
        template <typename... Ts>
        void f4(Ts&&... args)
        {
            auto param_list = std::array<int, sizeof...(Ts)>{ 
                std::forward<Ts>(args)...
            };
            x = param_list[0];
            y = param_list[1];
            z = param_list[2];
        }
    
        int x;
        int y;
        int z;
    };
    
    auto main() -> int
    {
        A a;
        a.f1(1, 2, 3);
        std::cout << a.x << ", " << a.y << ", " << a.z << "\n";
        a.f2(4, 5, 6);
        std::cout << a.x << ", " << a.y << ", " << a.z << "\n";
        a.f3(7, 8, 9);
        std::cout << a.x << ", " << a.y << ", " << a.z << "\n";
        a.f4(10, 11, 12);
        std::cout << a.x << ", " << a.y << ", " << a.z << "\n";
    }
    

    For f1 and f3 the parameter indices need to be compile time constants. f2 and f3 can use runtime dynamic indices, but might suffer from a bit more overhead during runtime. If performance is an issue, you should check the generated code - but modern compilers tend to optimize pretty well. I think dynamic indices can not be completely zero-overhead compared to directly referencing parameters by name.

    f3 and f4 are generic approaches for an arbitrary number of arguments. You might also want to restrict the allowed types for those functions. With C++20 this can easily be done with a concept, such as:

    #include <concepts>
    ...
    template <std::convertible_to<int>... Ts>
    

    With C++11 this can get a bit more cumbersome (maybe via static_assert and such).



  • A function receives its parameters under the declared names and there is no alternative name for them. If you define the function foo

    void foo (int x, int y, int z) {
    }
    

    the parameters of foo are only accessible via there names x, y and z. You can define an other type for the parameters like

    void foo (std::array<int,3>& paras) {
        int x(paras[0]), y(paras[1]), z(paras[2]);
    }
    

    Just an remark for better code. Never use names with leading _ oder __, these names are reserved for the implementation (the compiler).



  • @john-0 sagte in Access function's parameter by argument position:

    Just an remark for better code. Never use names with leading _ oder __, these names are reserved for the implementation (the compiler).

    A single leading underscore is okay as long as it is not followed by an uppercase character. But it's easier to just avoid them altogether.
    I tend to use trailing underscores instead.



  • @Finnegan sagte in Access function's parameter by argument position:

    A single leading underscore is okay as long as it is not followed by an uppercase character.

    For local variables/parameters, yes. In the global namespace anything starting with an underscore is reserved.

    But it's easier to just avoid them altogether.

    Agree.

    I tend to use trailing underscores instead.

    I decorate member variables instead of local variables/parameters. I use m_ as a prefix, because IMO it's much easier to see than using a suffix - especially one as subtle as a single _.

    But I think the important thing is to make it a habit to not use reserved identifiers.


Log in to reply