问题
EDITED: Let us suposse I have two (or more) template functions f
and g
that uses (some times) types depending on its template parameter:
template<typename T>
some_ugly_and_large_or_deep_template_struct_1<T>::type
f(const some_ugly_and_large_or_deep_template_struct_1<T>::type&,
const some_ugly_and_large_or_deeptemplate_struct_1<T>::type&)
{
// body, that uses perhaps more times my
// "some_ugly_and_large_or_deep_template_struct_1<T>"
}
template<typename T>
some_ugly_and_large_or_deep_template_struct_2<T>::type
g(const some_ugly_and_large_or_deep_template_struct_2<T>::type&,
const some_ugly_and_large_or_deeptemplate_struct_2<T>::type&)
{
// body, that uses perhaps more times my
// "some_ugly_and_large_or_deep_template_struct_2<T>"
}
How could I simplify this "type" definition?, for example with any of new C++11's tools? I think only on something like:
template<typename T,
typename aux = some_ugly_and_large_or_deep_template_struct_1<T>::type>
aux f(const aux&, const aux&)
{
// body, that uses perhaps more times my
// "aux" type
}
template<typename T,
typename aux = some_ugly_and_large_or_deep_template_struct_2<T>::type>
aux g(const aux&, const aux&)
{
// body, that uses perhaps more times my
// "aux" type
}
The problem that I see with this approach is the user can provide his own aux
type and not the type that I want.
回答1:
If you make it a variadic template, the caller has no possibility to define the type parameters listed after:
template<typename T,
typename..., // firewall, absorbs all supplied arguments
typename aux = some_ugly_and_large_or_deep_template_struct_1<T>::type>
aux f(const aux&, const aux&)
{
// body, that uses perhaps more times my
// "aux" type
}
Optionally, to prevent calling f
accidentally with too many template arguments, one can add a static_assert:
template<typename T,
typename... F,
typename aux = some_ugly_and_large_or_deep_template_struct_1<T>::type>
aux f(const aux&, const aux&)
{
static_assert(sizeof...(F)==0, "Too many template arguments");
// body, that uses perhaps more times my
// "aux" type
}
Usually, I can live with letting the user define types like aux
, being for example the return type where this can save you a cast.
Or you can replace the static_assert
with an enable_if
:
template<typename T,
typename... F, typename = typename std::enable_if<sizeof...(F)==0>::type,
typename aux = some_ugly_and_large_or_deep_template_struct<T>::type,>
aux f(const aux&, const aux&)
{
// body, that uses perhaps more times my
// "aux" type
}
回答2:
You could declare a template alias alongside the function:
template<typename T> using f_parameter
= typename some_ugly_and_large_or_deep_template_struct<T>::type;
template<typename T>
f_parameter<T> f(const f_parameter<T>&, const f_parameter<T>&)
{
f_parameter<T> param;
}
回答3:
You can use something like
namespace f_aux {
template <typename T> using type =
typename some_ugly_and_large_or_deep_template_struct<T>::type;
}
template <typename T>
f_aux::type<T> f(const f_aux::type<T>& , const f_aux::type<T>&);
If the declaration of f is in a suitable namespace or class, you may not need the additional f_aux
namespace.
回答4:
A possible solution would be to convert the template function into a template struct
with an operator()
. For example:
#include <iostream>
#include <string>
template <typename T>
struct some_ugly_and_large_or_deep_template_struct
{
typedef T type;
};
template <typename T>
struct f
{
typedef typename some_ugly_and_large_or_deep_template_struct<T>::type aux;
aux operator()(const aux& a1, const aux& a2)
{
return a1 + a2;
}
};
int main()
{
std::cout << f<int>()(4, 4) << "\n";
std::cout << f<std::string>()("hello ", "world") << "\n";
return 0;
}
来源:https://stackoverflow.com/questions/14648611/template-alias-in-template-function