1

I have the following testcase:

#include <type_traits>

template <typename Ty_>
using conditional_ref = 
    typename std::conditional<std::is_fundamental<Ty_>::value, Ty_, Ty_ const&>::type;

template <typename Ty_, typename Ty2_ = conditional_ref<Ty_>>
inline void f(Ty2_ arg1) {
  static_assert(std::is_same<Ty2_, conditional_ref<Ty_>>::value, "uh-oh!");
}

int main() {
  struct A {};
  A a{};
  double b{};

  //f(a);                                           // Cannot deduce parameter (expected)
  //f(b);                                           // Cannot deduce parameter (expected)
  f<decltype(a)>(a);                                // uh-oh!
  f<decltype(b)>(b);                                // OK
  f<decltype(a), conditional_ref<decltype(a)>>(a);  // OK
  f<decltype(b), conditional_ref<decltype(b)>>(b);  // OK

  return 0;
}

In this, f<decltype(a)> deduces to f<A, A> instead of the expected f<A, A const&>.
I have tried in clang-10, gcc-9, and Visual Studio 2019; all of these give the same result, so I think I'm doing something wrong.
Example output from clang-10:

$ clang-10 test.cpp
test.cpp:9:3: error: static_assert failed due to requirement 'std::is_same<A, const A &>::value' "uh-oh!"
  static_assert(std::is_same<Ty2_, conditional_ref<Ty_>>::value, "uh-oh!");
  ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:19:3: note: in instantiation of function template specialization 'f<A, A>' requested here
  f<decltype(a)>(a);                                // uh-oh!
  ^
1 error generated.

Why is the template deduction not what I expect here?

How do I rewrite f() so that it accepts a Ty_ when passed a fundamental type, and a Ty_ const& otherwise? Preferably while only having to pass the type of the argument once, like f<decltype(a)>(a).

vehystrix
  • 418
  • 5
  • 9

2 Answers2

2

Ty2_ is deducible, so default is not used at all. you might use directly:

template <typename Ty_>
void f(conditional_ref<Ty_> arg1) {
  static_assert(std::is_same<decltype(arg1), conditional_ref<Ty_>>::value, "uh-oh!");
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

Type of Ty2_ is deduced by provided argument of function call. You can disable this deduction by

void f(std::type_identity_t<Ty2_> arg1)

then default template parameter type will be used.

rafix07
  • 20,001
  • 3
  • 20
  • 33