mercredi 10 février 2021

Default template argument deducing to the wrong type in a conditional

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).

Aucun commentaire:

Enregistrer un commentaire