c++variadic-templatestemplate-meta-programmingtype-deductionforwarding-reference

How to separate type deduction from function parameter declaration?


I have measured a significant speedup in my application if my function foo accepts primitive types by value instead of by universal (forwarding) reference. The speedup is lost however, if non-primitive types are not passed by universal reference. If foo was accepting a fixed number of arguments, this would do the trick:

#include <cstdio>
#include <string>
#include <type_traits>

template <typename T>
requires (!std::is_scalar_v<std::decay_t<T>>)
auto foo(T&&){
    std::puts("pass by universal reference");
}

template <typename T>
requires std::is_scalar_v<std::decay_t<T>>
auto foo(T){
    std::puts("pass by value");
}

int main(){
    foo(42);  // pass by value
    foo(std::string{"hello"}); // pass by universal reference
    
    return 0;
}

However, the problem is that foo accepts a template parameter pack, and some parameters might be primitives while others might not. Thus, foo would have to deduce parameter types first and then, if they are not primitives, turn them into universal references. If foo was a class template, this could be achieved using deduction guides:

#include <cstdio>
#include <string>
#include <type_traits>

template <typename T>
using MaybeRef =
    std::conditional_t<std::is_scalar_v<std::decay_t<T>>, std::decay_t<T>, T&&>;

#include <tuple>
template <typename... Ts>
struct Foo {
    
    Foo(Ts...) {
        static_assert(std::is_same_v<std::tuple_element_t<0, std::tuple<MaybeRef<Ts>...>>, int>);
        static_assert(std::is_same_v<std::tuple_element_t<1, std::tuple<MaybeRef<Ts>...>>, std::string&>);
        std::puts("passed");
    }
};

template <typename... Ts>
Foo(Ts&&...) -> Foo<MaybeRef<Ts>...>;

int main(){
    std::string str = "hello";
    Foo{42, str};

    return 0;
}

However, I do not know how to achieve the same for my function foo. Is this even possible and how?


Solution

  • It's not possible to do this in current C++, but there are a number of relevant proposals: