c++parameter-passingparameter-pack

How to pass parameter pack by reference and pointer?


How to pass parameters to a function by reference and through a pointer?

I have an example in which I try to call one of two write functions of the CFoo class. The example compiles if I specify two "parameter pack" const Args1... a, const Args0... b separated by commas, but if I specify the call OnFoo(&CFoo::write, ....); then it will only work for one of the two cases. And if I swap the "parameter pack" const Args1... a, const Args0... b then the picture will be completely opposite, the other call will work.

How can I make both calls work or replace the two "parameter pack" with one, so that I can pass parameters both by reference and through a pointer?

class CFoo
{
public:
    static void write(const char& a, const char& b, const char& c)
    {
    }

    static void write(const char* a, const char* b, const char* c)
    {
    }
};

#define TYPE_FUNCTION const Args1*... a, const Args0&... b // Work for call with reference
// #define TYPE_FUNCTION const Args0&... a, const Args1*... b // Work for call with point

template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION)
{
}

int main(int argc, char** argv)
{
    OnFoo(&CFoo::write, '1', '1', '1');
    // OnFoo(&CFoo::write, "1", "1", "1");

    return 0;
}

First case

class CFoo
{
public:
    static void write(const char& a, const char& b, const char& c)
    {
    }

    static void write(const char* a, const char* b, const char* c)
    {
    }
};

#define TYPE_FUNCTION const Args1*... a, const Args0&... b // Work for call with reference

template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION)
{
}

int main(int argc, char** argv)
{
    OnFoo(&CFoo::write, '1', '1', '1');
    OnFoo(&CFoo::write, "1", "1", "1"); // Error

    return 0;
}

Error:

main.cpp: In function 'int main(int, char**)':
main.cpp:24:38: error: no matching function for call to 'OnFoo(<unresolved overloaded function type>, const char [2], const char [2], const char [2])'
   24 |     OnFoo(&CFoo::write, "1", "1", "1");
      |                                      ^
main.cpp:17:48: note: candidate: 'template<class ... Args0, class ... Args1> void OnFoo(void (*)(const Args1* ..., const Args0& ...), const Args1* ..., const Args0& ...)'
   17 | template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION)
      |                                                ^~~~~
main.cpp:17:48: note:   template argument deduction/substitution failed:
main.cpp:24:38: note:   mismatched types 'const Args0&' and 'const char*'
   24 |     OnFoo(&CFoo::write, "1", "1", "1");
      |                                      ^
main.cpp:24:38: note:   inconsistent parameter pack deduction with 'char' and 'char [2]'

Second case

class CFoo
{
public:
    static void write(const char& a, const char& b, const char& c)
    {
    }

    static void write(const char* a, const char* b, const char* c)
    {
    }
};

#define TYPE_FUNCTION const Args1&... a, const Args0*... b // Work for call with reference

template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION)
{
}

int main(int argc, char** argv)
{
    OnFoo(&CFoo::write, '1', '1', '1'); // Error
    OnFoo(&CFoo::write, "1", "1", "1");

    return 0;
}

Error:

main.cpp:23:42: error: no matching function for call to 'OnFoo(<unresolved overloaded function type>, char, char, char)'
   23 |         OnFoo(&CFoo::write, '1', '1', '1');
      |                                          ^
main.cpp:17:52: note: candidate: 'template<class ... Args0, class ... Args1> void OnFoo(void (*)(const Args1& ..., const Args0* ...), const Args1& ..., const Args0* ...)'
   17 |     template <class... Args0, class... Args1> void OnFoo(void (*func)(TYPE_FUNCTION), TYPE_FUNCTION)
      |                                                    ^~~~~
main.cpp:17:52: note:   template argument deduction/substitution failed:
main.cpp:23:42: note:   mismatched types 'const Args0*' and 'const char&'
   23 |         OnFoo(&CFoo::write, '1', '1', '1');
      |                                          ^
main.cpp:23:42: note:   mismatched types 'const Args0*' and 'char'

The difference between the first and second cases is that I swapped the "parameter pack" which is passed by reference and via a pointer.


Solution

  • You cannot pass overload set as parameter.

    So function parameter should be non-deducible,

    Then you might have function parameter depending of the other parameters, something like:

    template <class... Args>
    void OnFoo(std::conditional_t<(std::is_pointer_v<std::decay_t<Args>> && ...),
                                  void(*)(std::decay_t<Args>...),
                                void(*)(const Args&...)>,
                Args&&...)
    {
        // ...
    }
    

    Demo