neo-mashiro
neo-mashiro

Reputation: 534

How to add a parameter value when forwarding parameters to a variadic template function?

Suppose that I have two functions below, in the Foo() function, how can I pack the hw string into args and forward them to Bar()?

I tried std::bind but that didn't work.

template<typename T, typename... Args>
void Bar(Args&&... args) 
{
    // do something with args
}

template<typename T, typename... Args>
void Foo(Args&&... args)
{
    if (typeid(T) == typeid(std::string)) {
        std::string hw = "Hello, world!";
        Bar<T>(std::forward<Args>(hw, args)...);  // how to add hw to the forward list?
    }
    else {
        Bar<T>(std::forward<Args>(args)...);
    }
}

Edit: Finally I found my bug! For those of you who's wondering why hw doesn't get forwarded to Bar() even if you did it right, please pay attention to the Bar() in the else branch. If Bar() expects different types of arguments depending on T and the code won't compile, the compiler errors might be emitted by the else branch. As @JeJo mentioned, I should have used if constexpr instead.

You may find this post helpful: using std::is_same, why my function still can't work for 2 types

Upvotes: 3

Views: 487

Answers (2)

Tarkesh
Tarkesh

Reputation: 1

You need to pass hw as std::move(hw) separately to Bar function.

Upvotes: 0

JeJo
JeJo

Reputation: 32722

How to add hw to the forward list?

Simply

Bar<T>(hw, std::forward<Args>(args)...); 
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

or if you want to move the hw to Bar()

#include <utility>      // std::move, std::forward

Bar<T>(std::move(hw), std::forward<Args>(args)...); 
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

or let the compiler deduce the type T

Bar(std::move(hw), std::forward<Args>(args)...); 
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

for that, the Bar does not required the first template argument T

template<typename... Args>
void Bar(Args&&... args) 
{
    // ....
}

That being said, you might want to change the normal if statement with if constexpr for compile time branching, as follows:

#include <utility>      // std::move, std::forward
#include <type_traits>  // std::is_same_v

template<typename T, typename... Args>
void Foo(Args&&... args) 
{
    if constexpr (std::is_same_v<T, std::string>)
    {
        std::string hw = "Hello, world!";
        Bar(std::move(hw), std::forward<Args>(args)...);  
    }
    else
    {
        Bar(std::forward<Args>(args)...);
    }
}

Here is the complete demo

Upvotes: 7

Related Questions