Question

In the code below, the class template uses one parameter but the function template uses two if the template argument is a template. This is ok when using type deduction but odd when using explicit template instantiation.

Is is possible to write the template template parameter as one single parameter?

This question is linked to function overload matching template template

#include <iostream>

template <typename T>
struct C
{
    C (T i)
    {
        std::cout << "simple" << std::endl;
    }
};
template <template<typename TT> class FF, typename TT>
struct C <FF<TT> >          // (1)
{
    C (FF<TT> i)
    {
        std::cout << "template" << std::endl;
    }
};
template <typename T>
void F (T i)
{
    std::cout << "simple" << std::endl;
}

// two template arguments FF and TT.
// Anyway to write this so that the argument count is one?
template <template<typename TT> class FF, typename TT>
void F (FF<TT> i)
{
    std::cout << "template" << std::endl;
}

template <typename T>
struct R
{
    T x;
};
int main()
{
        R<int>     r;
        C<R<int> >{r};      // prints 'template', as expected
        F<R<int> >(r);      // prints 'simple',  probably not what you think
        F<R,int  >(r);      // prints 'template' as expected but 
}

EDIT:

I came to the conclusion that the question is not a good one because if there where a one parameter syntax, the overload resolution would still pick the wrong function. This comes as a surprise to me but here is the code that proves it (same code as before except one template function overload that changed):

EDIt2: added a further print in the main skipping the explicit template specification.

EDIT3: The code below is nonsense. I made a mistake as @DyP pointed out correctly. I am calling void F(R<R<T>>) in the explicit case and not void F(R<T>) .

#include <iostream>

template <typename T>
struct R
{
    T x;
};
template <typename T>
struct C
{
    C (T i)
    {
        std::cout << "simple" << std::endl;
    }
};
template <template<typename TT> class FF, typename TT>
struct C <FF<TT> >          // (1)
{
    C (FF<TT> i)
    {
        std::cout << "template" << std::endl;
    }
};
template <typename T>
void F (R<T> i)
{
    std::cout << "template" << i.x << std::endl;
}
template <typename T>
void F (T i)
{
    std::cout << "simple" << std::endl;
}
int main()
{
        R<int>     r;
        C<R<int> >{r};      // prints 'template', as expected
        F<R<int> >(r);      // prints 'simple',  probably not the expected overload
        F         (r);      // prints 'template', now overload resolution works. Strange.
}
Was it helpful?

Solution

With SFINAE:

#include <type_traits>

template<class T>
struct is_template_with_one_param
: std::false_type
{};

template<template<class> class TT, class T>
struct is_template_with_one_param< TT<T> >
: std::true_type
{};


#include <iostream>

template <typename T>
typename std::enable_if< not is_template_with_one_param<T>{}, void >::type
F (T i)
{
    std::cout << "simple" << std::endl;
}

template <typename T>
typename std::enable_if< is_template_with_one_param<T>{}, void >::type
F (T i)
{
    std::cout << "template" << std::endl;
}

usage example:

template <typename T>
struct R
{
    T x;
};
int main()
{
        F(R<int>{});
        F(42);
}

Alternatively, consider Jarod42's suggestion.

OTHER TIPS

Another possible solution:

#include <iostream>

template <typename T>
struct C
{
    C (T i)
    {
        std::cout << "simple" << std::endl;
    }
};
template <template<typename TT> class FF, typename TT>
struct C <FF<TT> >          // (1)
{
    C (FF<TT> i)
    {
        std::cout << "template" << std::endl;
    }
};

template <typename T>
void F (T i)
{
    C<T> x(i);
}

template <typename T>
struct R
{
    T x;
};
int main()
{
        R<int>     r;
        F(r);
        F(4);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top