Dec 14, 2016

[C++] [template] Ts... during template function argument type matching will generate sizeof...(Ts) == 0 is argument is not dependent

Google ISO C++ Standard - Discussion
Variant's trap when overloading operator<<


#include <iostream>
#include <sstream>

template <class... Ts>
struct Y
{
    static_assert(sizeof...(Ts)>0, "!");
    // assert here due to
    // operator<< will try to instantiate Y<Ts...> to match
    // std::endl with sizeof...(Ts) == 0;
    // If it's T instead of Ts..., T will not be matched and
    // simply an SFINAE and fall back to main template function
    // operator <<

};


template <class... Ts>
std::ostream& operator<<(std::ostream& os, Y<Ts...> const& )
{
    return os << std::endl;
}


// Match to &std::endl; which endl is a template function.
std::basic_ostream<char, std::char_traits<char> >& (*endl)
    (std::basic_ostream<char, std::char_traits<char> >&) = &std::endl;


// Same as above, difference is using typename T to match
// template function std::endl;
template<typename T>
std::basic_ostream<T, std::char_traits<T> >& (*endl_2)
    (std::basic_ostream<T, std::char_traits<T> >&) = &std::endl;


// ---------------------------------


template<typename T, typename U = T>
struct Fun{

};


// Mark out main template to prevent SFINAE
/*template<typename T>
void ha(T t){}*/


template<typename T>
void ha(Fun<T> f){
    /*ha(std::endl);*/
    ha(2.0);
}


template<typename... T>
void ha2(Fun<T...> f){
    ha2(2.0);
}


int main()
{
 // call template operator <<
    operator <<(std::cout, Y<int>{});
}

/*
 Error:
test.cpp:7:5: error: static_assert failed "!"
    static_assert(sizeof...(Ts)>0, "!");
    ^             ~~~~~~~~~~~~~~~
test.cpp:21:18: note: in instantiation of template class 'Y<>' requested here
    return os << std::endl;
                 ^
test.cpp:53:5: error: no matching function for call to 'ha'
    ha(2.0);
    ^~
test.cpp:51:6: note: candidate template ignored: could not match 'Fun<type-parameter-0-0, type-parameter-0-0>' against 'double'
void ha(Fun<T> f){
     ^
test.cpp:59:5: error: no matching function for call to 'ha2'
    ha2(2.0);
    ^~~
test.cpp:58:6: note: candidate template ignored: could not match 'Fun<type-parameter-0-0...>' against 'double'
void ha2(Fun<T...> f){
     ^
3 errors generated.
 */

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.