В приведенном ниже коде шаблон класса использует один параметр, а шаблон функции — два, если аргумент шаблона является шаблоном. Это нормально при использовании вывода типа, но странно при использовании явной реализации шаблона.
Можно ли записать параметр шаблона шаблона как один единственный параметр?
Этот вопрос связан с шаблон перегрузки соответствия шаблон
#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
}
РЕДАКТИРОВАТЬ:
Я пришел к выводу, что вопрос не очень хороший, потому что, если там есть синтаксис с одним параметром, разрешение перегрузки все равно выберет неправильную функцию. Это удивляет меня, но вот код, который это подтверждает (тот же код, что и раньше, за исключением одной перегрузки функции шаблона, которая изменилась):
EDIt2: добавлен дальнейший вывод в основной текст пропуска явной спецификации шаблона.
РЕДАКТИРОВАТЬ3: код ниже это ерунда. Я сделал ошибку, так как @DyP указал правильно. я звоню void F(R<R<T>>)
в явном случае, а не 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.
}
С СФИНА:
#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;
}
пример использования:
template <typename T>
struct R
{
T x;
};
int main()
{
F(R<int>{});
F(42);
}
В качестве альтернативы рассмотрим Jarod42«s предложение.
Другое возможное решение:
#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);
}