Based on your last example, we would get:

#include <vector>

#include <set>

#include <string>

 

template<typenamestruct no_default_alias3;

 

template<> struct no_default_alias3<int> {

   using type = std::vector<int>;

};

 

template<typename T> using alias3 = typename no_default_alias3<T>::type;

 

template<typename T> void bar(T a, alias3<T>) { }

 

template<> struct no_default_alias3<float> {

   using type = std::vector<int>;

};

 

template<> struct no_default_alias3<bool> {

   using type = std::set<std::string>;

};

 

void foo()

{

   bar(1.0f, std::vector<int>{});

   bar(true, std::set<std::string>{});

}


Nicolas


Sent from my iPhone

On 19 Nov 2021, at 16:16, Arthur O'Dwyer via Std-Proposals <std-proposals@lists.isocpp.org> wrote:


On Fri, Nov 19, 2021 at 10:07 AM Nicolas Weidmann via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Thank you for your replies.
But the problem you are raising with your example already exists now:

template<typenamestruct no_default_alias3;

 

template<> struct no_default_alias3<int> {

   using type = std::vector<int>;

};

 

template<typename T> using alias3 = typename no_default_alias3<T>::type;

 

template<typename T> void bar(alias3<T>) { }


Here the signature of `bar` (looking through the "transparent" aliases) is

    template<typename T> void bar(no_default_alias3<T>::type) { }

The template parameter `T` cannot be deduced, because it's "firewalled" behind a member typedef of a dependent type. This is the primary use-case for C++20 `std::identity` — as a type-deduction firewall:

    template<class T> void baz1(T a, T b);
    template<class T> void baz2(T a, typename std::identity<T>::type b);
    int main() {
        baz1(sizeof(int), 0);  // deduction fails: `a` says T=size_t but `b` says T=int
        baz2(sizeof(int), 0);  // deduction succeeds: `a` says T=size_t, and `b` does not contribute to deduction
    }

We also define
    template<class T> identity_t = typename std::identity<T>::type;
as an alias template so that we don't have to write out the whole long thing every time. This is "free" because the compiler will just look straight through aliases: `identity_t<T>` is exactly equivalent to `std::identity<T>::type` in every place it's written.

HTH,
Arthur
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals