Can a template parameter itself be templatized? - c++

Say I have the following code:
#include <iostream>
#include <functional>
template <int func(int)>
struct S : std::unary_function<int, int>
{
int operator()(int x) const
{
return func(x);
}
};
int foo(int x)
{
return x;
}
int main()
{
S<foo> s;
std::cout << s(42) << std::endl;
}
This works okay as a way of wrapping up a function inside of a functor, which means it can be used in other templated functions (like sort, for example (assuming the functor had the right signature)). I don't want to create a functor struct for every possible return/argument type (and realistically I can't), and so I tried the following:
template <template <typename R, // Make the return type and argument type template parameters!
typename A> R func(A)>
struct S : std::unary_function<R, A>
{
R operator()(A arg) const
{
return func(arg);
}
};
That didn't work; it gave me compilation errors. So then I tried:
template <typename R, typename A, R func(A)>
struct S : std::unary_function<R, A>
{
R operator()(A arg) const
{
return func(arg);
}
};
Which did work. Unfortunately though, I had to change instantiations of S to be S<int, int, foo> s; instead of the nicer S<foo> s;.
Is it at all possible to templatize the function passed as a template argument such that I can do S<foo> s; and not hard code the return type and argument type of the function in S?
My google-foo hasn't been able to find a specific answer.
Edit: Now I'm wondering if this isn't possible. I just thought of "what if foo is an overloaded function?" There wouldn't be, as far as I know, a way to know which foo to use when saying S<foo> s; and thus explicitly stating return/argument type is necessary. Is this correct thinking, and does this mean that the answer to my first question is "No, it's not possible"?

Unfortunately, I think it's the only way to prevent necessary conversions for passing functions.
But you can add function templates to help you deduce the types of (1) function args (2) function returns, like codes below:
template < typename R, typename A >
R result_of( R(A) );
template < typename R, typename A >
A arg0_of( R(A) );
Then you can use them to construct wanted function objects and let compilers do possible optimizations:
#define get_call( f ) call_t< decltype(result_of(f)), \
decltype(arg0_of(f)), f >()
// same as the class 'S'
template < typename R, typename A,
R unary( A ) >
struct call_t : std::unary_function<A,R> {
R operator()( A arg ) const {
return unary( arg );
}
};
Use the utility:
int neg( int arg ) {
return -arg;
}
auto s = get_call( neg );
cout << s( 1 ) << endl; // outputs: -1
It works too on function templates. Of course, you have to pass argument(s) to the template:
template < typename T >
T square( T arg ) {
return arg * arg;
}
template <>
int square( int arg ) {
cout << "square<int>()" << endl;
return arg * arg;
}
auto sq = get_call( square<int> );
cout << sq( 12 ) << endl; // outputs: square<int>()
// 144
Edit: for overloaded functions, you can do conversions to tell compilers which version you wanna invoke:
int cube( int arg ) {
return arg * arg * arg;
}
float cube( float arg ) {
return arg * arg * arg;
}
typedef float (*chosen)( float );
auto cu = get_call( (chosen)cube );
cout << showpoint << cu( 4 ) << endl; // outputs: 64.0000

You seem to want to have a non-type template template parameter. However, the only legal syntax for template template parameters is template < template-parameters > class. ("A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression." § 14.3.3)
You could create a templated class whose constructor argument was a function pointer, but I'm guessing that you're worried that will create an indirect function call.

That is not possible. It is the same problem in principle as the following one: you wish to write just A<100> where A is defined as:
template<T N>
struct A {};
Given N is 100, T turns out to be int. Fine. That is deducible by human mind, but not by the compilers even if they be 100% conformant to the C++11 Standard. I've exactly the same problem here:
Pretty-print types and class template along with all its template arguments
--
So the alternative solution I think is this:
template <typename R, typename A>
struct S : std::unary_function<R, A>
{
typedef R (*Fun)(A);
Fun func;
S(Fun f) : func(f) {}
R operator()(A arg) const
{
return func(arg);
}
};
And then define MakeS function as:
template<typename R, typename A>
S<R,A> MakeS(R (*fun)(A))
{
return S<R,A>(fun);
}
Which you can use it as:
auto s = MakeS(foo);
Or, simply this:
S<int,int> s(foo);
The downside with this alternative is that the function foo doesn't have any chance to be inlined now.

Does this work for you?
It may not be as nice as S<foo> but keeps the arguments as 1 at the point of instantiation.
int f(int) { return 0; }
template<class R, class A> struct S
{
typedef R(*FTYPE)(A);
typedef R RET;
typedef A ARG;
};
template<class R, class A> S<R, A> FW(R(f)(A));
template<class T> struct F : std::unary_function<typename T::RET, typename T::ARG>
{
};
int main()
{
F<decltype(FW(f))> o;
}

Related

How to get number of function arguments from `decltype(<funtion>)`?

Let's say I have the following function declaration:
template<typename signature>
int foo();
Given the above-mentioned function, is it possible to define foo in such a way, so that it returns the number of function arguments that were passed in the decltype template parameter?
So the example usage might look like:
int bar(int a, int b)
{
return a + b;
}
int jar(int a)
{
return a * a;
}
int main()
{
std::cout << foo<decltype(bar)>() << std::endl; // Desired output: 2
std::cout << foo<decltype(jar)>() << std::endl; // Desired output: 1
}
Edit:
Thanks, everyone for the replies. They do seem to work. However, I forgot to mention one more use case.
Let's say I want to get the number of arguments of the following function:
int __stdcall car(int a, int b, int c)
{
return a * b + c;
}
The answers so far do not seem to work with this kind of function that uses __stdcall convention.
Any idea why and what can be done about it?
For that(i.e. with decltype), the given foo is not enough. You need something like the followings traits.
template<typename> struct funtion_args final {};
template<typename ReType, typename... Args>
struct funtion_args<ReType(Args...)> final
{
static constexpr std::size_t noArgs = sizeof...(Args);
};
Used sizeof... operator on the variadic template arguments, to get the no of arguments.
And then you can get the argument count directly like
std::cout << funtion_args<decltype(bar)>::noArgs << "\n"; // output: 2
or pack into the foo
template<typename signature>
constexpr std::size_t foo() noexcept
{
return funtion_args<signature>::noArgs;
}
(See Live Demo)
Better Approach
If you want less typing(i.e. without decltype), a more convenient way of getting the arguments count of a free-function, you could do the following
template <typename ReType, typename... Args>
constexpr auto foo(ReType(*)(Args...)) noexcept
{
return sizeof...(Args);
}
Now you could conveniently call the foo with other functions as arguments
std::cout << foo(bar) << "\n"; // output: 2
(See Live Demo)
Sure, just have foo() call on a suitable trait type. For example:
template <typename T>
struct foo_helper;
template <typename T, typename... Args>
struct foo_helper<T(Args...)> {
static constexpr std::size_t arg_count = sizeof...(Args);
};
template <typename T>
std::size_t foo() {
return foo_helper<T>::arg_count;
}

Deduction Guide for a template template parameter

I have a set of structure's class as such:
template<typename T>
struct Foo {
T x_;
T y_;
constexpr Foo(T x, T y) : x_{x}, y_{y} {}
};
template<typename T, typename U, template<U> class Func>
class Bar {
private:
Foo<T> foo_;
Func<U> func_
size_t n_;
public:
Bar(Foo<T> foo, size_t n, Func<U> func) :
foo_{foo},
n_{n},
func_{func}
{}
};
And I'm trying to create a deduction guide for this class template...
// Doesn't compile
template<typename T, typename U, template<U> class Func>
Bar(Foo<T>, U, Func<U>)->
Bar<T,U,Func>;
// Doesn't compile
template<typename T, typename U, template<U> class Func>
Bar(Foo<T>, U, Func)->
Bar<T,U,Func>;
I'm not sure of the proper syntax for this when the template argument happens to be a template itself where that templated argument will be a function pointer, function object, functor, or a lambda that the class will store.
When I try to use U within Func<> it states "type name is not allowed" and if I remove it to be just Func without any template arguments, it states, "argument list for template template parameter 'Func' is missing"...
My intended use of Bar looks like this:
template<typename T>
constexpr T funcA(T x) {
return x;
}
template<typename T>
constexpr T funcB(T x) {
return x*x;
}
int main() {
Bar bar1{Foo{1.0, 3.0}, 1000, funcA<double>};
Bar bar2{Foo{3.7, 4.0}, 500, funcB<float>};
return 0;
}
EDIT - This section is intended for user: piotr-skotnicki
Note: The above was a pseudo code with the same signatures as a representation of my classes... Now that I have access to my IDE again, here is the "real" source.
Integrator.h
#pragma once
//#include <type_traits>
template <typename Field>
struct Limits {
Field lower;
Field upper;
constexpr Limits(Field a = 0, Field b = 0) :
lower{ a < b ? a : b },
upper{ a < b ? b : a }
{}
};
template <typename LimitType, typename Func>
class Integrator {
//static_assert(std::is_invocable_v<Func&>, "Invalid callable");
private:
Limits<LimitType> limits_;
size_t step_size_;
Func integrand_;
public:
Integrator(Limits<LimitType> limits, size_t stepSize, Func integrand) :
limits_{ limits },
step_size_{ stepSize },
integrand_{ integrand }
{}
constexpr auto evaluate() {
auto distance = limits_.upper - limits_.lower;
auto dx = distance / step_size_;
return calculate(dx);
}
private:
template<typename ValueType>
constexpr auto calculate(ValueType dx) {
ValueType result = 0.0;
for (size_t i = 0; i < step_size_; ++i) {
auto dy = integrand_(limits_.lower + i * dx);
auto area = dy * dx;
result += area;
}
return result;
}
};
//template <typename LimitType, typename Func>
//Integrator(Limits<LimitType>, size_t, Func)
//->Integrator<LimitType, Func>;
main.cpp
#include <iostream>
#include <exception>
#include "Integrator.h"
double funcE(double x) {
return x;
}
template <typename T>
constexpr T funcA_t(T x) {
return x;
}
// This Works!
int main() {
try {
std::cout << "Integration of f(x) = x from a=3.0 to b=5.0\nwith an expected output of 8\n";
Integrator integratorA{ Limits{3.0, 5.0}, 10000, funcA };
std::cout << integratorA.evaluate() << '\n';
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
// This was failing to compile... but now seems to work for some reason...
int main() {
try {
std::cout << "Integration of f(x) = x from a=3.0 to b=5.0\nwith an expected output of 8\n";
Integrator integratorA{ Limits{3.0, 5.0}, 10000, funcA_t<double> };
std::cout << integratorA.evaluate() << '\n';
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
// Same as above...
Integrator integrator{ Limits{3.0, 5.0}, 10000, &funcA_t<double> };
// wasn't compiling...
Beforehand Visual Studio was complaining that it couldn't deduce template argument Func... and I don't know why...
I don't know what was going on... maybe Visual Studio was acting up... It appears to be working now... very odd...
First of all, the below syntax:
template <typename T, typename U, template <U> class Func>
doesn't mean that Func will have a single type template argument, the same as the second template argument U of a Bar instance itself.
It means that Func is a class template that takes a non-type template parameter of type U. If Func requires a type template parameter, that should become:
template <typename T, typename U, template <typename> class Func>
// ~~~~~~~^
And a matching deduction guide:
template <typename T, typename U, template <typename> class Func>
Bar(Foo<T>, U, Func<U>) -> Bar<T, U, Func>;
However, Func remains a template template parameter, and accepts only alias/class/struct templates, and that will never match a function pointer type, nor a lambda expression. If you indend to store any callable object inside Bar instances, then use any type as a template parameter, and let the deduction guide deduce which is it:
template <typename T, typename U, typename Func>
// ~~~~~~~^
In order to make sure that it will be callable with an (lvalue) argument of type U, just put a constraint like a static_assert:
#include <type_traits>
template <typename T, typename U, typename Func>
class Bar {
static_assert(std::is_invocable_v<Func&, U&>, "Invalid callable");
private:
Foo<T> foo_;
Func func_;
U n_;
public:
Bar(Foo<T> foo, U n, Func func) :
foo_{foo},
func_{func},
n_{n}
{}
};
DEMO
Also note that you don't need an explicit deduction guide, as one will be generated implicitly from the constructor.
However, if you don't know in advance what U will be used as an argument to Func, then that shouldn't be considered as a problem in the constructor definition, nor in the class definition itself. It's a clear indication that the argument will be supplied from some external source, and at some place you will know and will be able to verify whether it fits the callable or not.
For sure, you should not be trying to deduce the exact signature of a callable object. It's useless in practice and most probably means there's a flaw in your design.
That is, once you eventually know what type of an argument is used, put a static_assert there, e.g.:
template <typename ValueType>
constexpr auto calculate(ValueType dx) {
static_assert(std::is_invocable_v<Func&, ValueType&>, "Invalid value type");
ValueType result = 0.0;
// ...
return result;
}
Alternatively, you can make calculate SFINAE-friendly with std::enable_if_t or requires:
template <typename ValueType>
constexpr auto calculate(ValueType dx)
-> std::enable_if_t<std::is_invocable_v<Func&, ValueType&>, ValueType> {
ValueType result = 0.0;
// ...
return result;
}

Functions and functors as arguments to template functions

I'm looking for a way to pass function pointers, functors or lambdas to a template function g which uses the passed function's argument types, for example:
template<class T1, class T2, class T3>
struct wrapper_t {
boost::function<void(T1,T2,T3)> f;
wrapper_t( boost::function<void(T1,T2,T3)> f ) : f(f) {}
void operator( std::vector<T1> &a, std::vector<T2> &b, T3 c ) {
assert(a.size() == b.size());
for(size_t i = 0 ; i != a.size() ; i++) f(a[i], b[i], c);
}
};
template<class T1, class T2, class T3>
wrapper_t<T1,T2,T3> make_wrapper( boost::function<void(T1,T2,T3)> f ) {
return wrapper_t<T1,T2,T3>( f );
}
void f(int, double, char) {};
wrapper_t<int, double, char> w0(f); // need to repeat types
auto w1 = make_wrapper(f); // more comfortable
std::vector<int> a{{1, 2, 3}};
std::vector<double> b{{1.0, 2.0, 3.0}};
w0( a, b, 'c' );
w1( a, b, 'c' );
The make_wrapper function only exists to extract the types from the argument, some syntactic sugar to avoid having to type them twice.
A minimal example for my problem is this function:
template<class T>
void g1( const boost::function<void(T)> & ) {}
Using these as input
void f1(int) {}
struct f2_t { void operator()(int) {} };
it fails to infer T=int
f2_t f2;
g1( f1 ); // mismatched types ‘const std::function<void(T)>’ and ‘void(int)’
g1( f2 ); // ‘f2_t’ is not derived from ‘const std::function<void(T)>’
g1( [](int){} ); // ‘::<lambda(int)>’ is not derived from ‘…
g1<int>( f1 ); // ok
g1<int>( f2 ); // ok
g1<int>( [](int){} ); // ok
But T=int can be inferred from a plain function pointer, but of this doesn't work with the functor or lambda either:
template<class T>
void g2( void (*)(T) ) {}
g2( f1 ); // ok
g2( f2 ); // mismatched types …
g2<int>( f2 ); // ok
g2( [](int){} ); // mismatched types …
g2<int>( [](int){} ); // ok
Is there a way to infer T not just for plain function pointers but for functors and lambdas, too?
Or does it have to be something like this?
template<class F>
void g( F ) { typedef first_argument_of<F>::type T; }
(in my real code I need to deconstruct a function with four arguments this way, but std::function::…argument_type only exists for one or two arguments; boost::function has argN_type, but I don't think I can use that anyway since F is not always a function which is my problem, see above, etc)
There is no way to do what you want for a variety of reasons. But here is one that should make the problem pretty clear:
struct function_object
{
template<typename ...T>
void operator ()(T&&... v){}
};
f( function_object{} );
What is the type of the arguments of the function object passed to f? There isn't any, it can be called with any kind and number of arguments.
I also think there is no direct way to define the template parameters and function arguments of a single, primary template definition such that T can be deduced in all the different situations (function pointer, lambda expression, std::function argument etc.).
I would therefore recommend that you follow the approach suggested at the end of your question. Indeed neither std::function nor the tools offered by Boost (as far as I know) will easily enable this, though.
What I use (and I learnt that from other SO posts in the past), is a rather complicated template function_traits with specializations for all the different cases. My definition is this:
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{ };
template <typename Return, typename... Args>
struct function_traits<Return(Args...)>
{
typedef std::size_t size_type;
typedef Return result_type;
typedef result_type function_type(Args...);
static constexpr size_type arity = sizeof...(Args);
template <size_type index>
struct arg
{
typedef typename std::tuple_element<index,std::tuple<Args...>>::type type;
};
static constexpr bool value = true;
};
template <typename Return, typename... Args>
struct function_traits<Return(*)(Args...)>
: function_traits<Return(Args...)>
{ };
template <typename Return, typename... Args>
struct function_traits<Return(&)(Args...)>
: function_traits<Return(Args...)>
{ };
template <typename Class, typename Return, typename... Args>
struct function_traits<Return(Class::*)(Args...)>
: function_traits<Return(Args...)>
{ };
template <typename Class, typename Return, typename... Args>
struct function_traits<Return(Class::*)(Args...) volatile>
: function_traits<Return(Args...)>
{ };
template <typename Class, typename Return, typename... Args>
struct function_traits<Return(Class::*)(Args...) const>
: function_traits<Return(Args...)>
{ };
template <typename Class, typename Return, typename... Args>
struct function_traits<Return(Class::*)(Args...) const volatile>
: function_traits<Return(Args...)>
{ };
To make using this even more convenient, you may want to define using-aliases:
template <typename Fun>
using result_of = typename function_traits<Fun>::result_type;
template <typename Fun, std::size_t index>
using arg = typename function_traits<Fun>::template arg<index>::type;
With all these definitions (which in the below, I assume you put into a separate header more_type_traits.hpp), you can then easily define your wrapper function as follows:
#include <iostream>
#include <functional>
#include <type_traits>
#include "more_type_traits.hpp"
template <typename Fun>
using noref = typename std::remove_reference<Fun>::type;
template <typename Fun>
result_of<noref<Fun>> fun(Fun &&argfun)
{
// Default-initialize the first argument
arg<noref<Fun>,0> arg {};
// Call the function
return argfun(arg);
}
The below (which is basically copied from your code) then compiles and works for me:
void f1(int i)
{ std::cout << "f1(" << i << ')' << std::endl; }
struct f2_t
{
void operator()(int i)
{ std::cout << "f2(" << i << ')' << std::endl; }
};
int main()
{
fun(f1);
f2_t f2;
fun(f2);
std::function<void(int)> funobj = [](int i)
{ std::cout << "funobj(" << i << ')' << std::endl; };
fun(funobj);
fun( [](int i) { std::cout << "lambda(" << i << ')' << std::endl; } );
return 0;
}
Clearly, the definition of function_traits is complicated, because many different specializations are required. But it's worth the effort if you want to make function wrapping convenient.
Lets suppose I read in a comment that the OP really wants to take a function that mutates a T, and turn it into a function that mutates a std::vector<T>, and thinks that in order to do this you need to know what T is.
You don't
#include <type_traits>
#include <utility>
template<typename Lambda>
struct container_version {
Lambda closure;
container_version( container_version const& ) = default;
container_version( container_version && ) = default;
container_version( container_version & ) = default;
template<typename U>
container_version( U&& func ):closure(std::forward<U>(func)) {};
// lets make this work on any iterable range:
template<typename Container>
void operator()( Container&& c ) const {
for( auto&& x:c )
closure(x);
}
};
template<typename Lambda>
container_version< typename std::decay<Lambda>::type >
make_container_version( Lambda&& closure ) {
return {std::forward<Lambda>(closure)};
}
#include <vector>
#include <iostream>
#include <functional>
#include <array>
int main() {
std::vector<int> my_vec = {0, 1, 2, 3};
for (auto x:my_vec)
std::cout << x << ",";
std::cout << "\n";
make_container_version( []( int& x ) { x++; })( my_vec );
for (auto x:my_vec)
std::cout << x << ",";
std::cout << "\n";
// hey look, we can store it in a `std::function` if we need to:
auto super_func = make_container_version( []( int& x ) { x++; } );
std::function< void( std::vector<int>& ) > func = super_func;
// and the same super_func can be used for a function on a different container:
std::function< void( std::array<int,7>& ) > func2 = super_func;
func(my_vec);
for (auto x:my_vec)
std::cout << x << ",";
std::cout << "\n";
}
In fact, taking the argument and turning it into a std::function, or forcing it to be stored in a std::function, costs efficiency, increases the complexity of the code, and makes it unable to do things that it has no problem doing.
The above version, before it is packed into a std::function, can operate on sets, lists, vectors , raw C arrays, std::arrays, etc.

Unrolling loops using templates in C++ with partial specialization

I'm trying to use templates to unroll a loop in C++ as follows.
#include <iostream>
template< class T, T i >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T >
struct printDown< T, 0 > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
When I compile w/ g++ 3.4.4 in Cygwin, I get the following error.
tmp.cpp:12: error: type T' of
template argument0' depends on
template parameter(s)
What am I doing wrong? Do I need to somehow annotate the 0 to say that it's of type T?
Thanks in advance.
Have you tried int i instead of T i?
Why this happens? From 14.5.5/8,
— The type of a template parameter
corresponding to a specialized
non-type argument shall not be
dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
Therefore when you apply partial specialization, the type of 0 is T (dependent on a parameter of the specialization). There are two choices, one is to make it none dependent, e.g., change T i to int i, and second is to apply explicit specialization rather than partial specialization.
Both solutions have been given out by others, so I'm not gonna to repost them here. At least you know the reason. It's defined by standard.
As pointed out by phooji your implementation suffers from a small issue: it quickly generates a long list of calls, which will make compilers choke quickly.
You could work around this by implementing a slightly more complicated version, using binary decomposition. I'll make it generic on a functor too, cause I am lazy.
// Signature
template <Functor F, unsigned N>
struct UnrolledLoop;
We need a helper template, which keeps an offset of the parameter to pass
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl;
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 0, OffSet>
{
static F run(F f) { return f; }
};
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 1, OffSet>
{
static F run(F f) { f(OffSet); return f; }
};
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl
{
static F run(F f) {
F f2 = UnrolledImpl<F, N/2, OffSet>::run(f);
return UnrolledImpl<F, N - N/2, OffSet + N/2>::run(f2);
}
};
And you can implement UnrolledLoop simply:
template <Functor F, unsigned N>
struct UnrolledLoop
{
static F run(F f) { return UnrolledImpl<F, N, 0>::run(f); }
}
Note that you could provide specialization for more values of N (3, 4 for example) to be nicer on the compiler.
What about adding this to your example:
template struct printDown< int, 0 >{
static void run(void) {
std::cout << 0 << "\n";
} };
The compiler cannot cast 0 to int automatically without knowing T's type in advance.
Just found this out. Apparently one can do something like this.
template< class T, T i, bool b = (i == 0) >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, true > {
static void run(void) {
std::cout << 0 << "\n";
}
};
I had no idea that could be done. Very Prologish & very nice.
You can make the parameter a type parameter to work this around
template< bool > struct bool_ { };
template< class T, T i, typename = bool_<true> >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, bool_<i == 0> > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
This way you can specify any conditions you want in the partial specializations.

Default template arguments for function templates

Why are default template arguments only allowed on class templates? Why can't we define a default type in a member function template? For example:
struct mycclass {
template<class T=int>
void mymember(T* vec) {
// ...
}
};
Instead, C++ forces that default template arguments are only allowed on a class template.
It makes sense to give default template arguments. For example you could create a sort function:
template<typename Iterator,
typename Comp = std::less<
typename std::iterator_traits<Iterator>::value_type> >
void sort(Iterator beg, Iterator end, Comp c = Comp()) {
...
}
C++0x introduces them to C++. See this defect report by Bjarne Stroustrup: Default Template Arguments for Function Templates and what he says
The prohibition of default template arguments for function templates is a misbegotten remnant of the time where freestanding functions were treated as second class citizens and required all template arguments to be deduced from the function arguments rather than specified.
The restriction seriously cramps programming style by unnecessarily making freestanding functions different from member functions, thus making it harder to write STL-style code.
To quote C++ Templates: The Complete Guide (page 207):
When templates were originally added to the C++ language, explicit function template arguments were not a valid construct. Function template arguments always had to be deducible from the call expression. As a result, there seemed to be no compelling reason to allow default function template arguments because the default would always be overridden by the deduced value.
So far, all the proffered examples of default template parameters for function templates can be done with overloads.
AraK:
struct S {
template <class R = int> R get_me_R() { return R(); }
};
could be:
struct S {
template <class R> R get_me_R() { return R(); }
int get_me_R() { return int(); }
};
My own:
template <int N = 1> int &increment(int &i) { i += N; return i; }
could be:
template <int N> int &increment(int &i) { i += N; return i; }
int &increment(int &i) { return increment<1>(i); }
litb:
template<typename Iterator, typename Comp = std::less<Iterator> >
void sort(Iterator beg, Iterator end, Comp c = Comp())
could be:
template<typename Iterator>
void sort(Iterator beg, Iterator end, std::less<Iterator> c = std::less<Iterator>())
template<typename Iterator, typename Comp >
void sort(Iterator beg, Iterator end, Comp c = Comp())
Stroustrup:
template <class T, class U = double>
void f(T t = 0, U u = 0);
Could be:
template <typename S, typename T> void f(S s = 0, T t = 0);
template <typename S> void f(S s = 0, double t = 0);
Which I proved with the following code:
#include <iostream>
#include <string>
#include <sstream>
#include <ctype.h>
template <typename T> T prettify(T t) { return t; }
std::string prettify(char c) {
std::stringstream ss;
if (isprint((unsigned char)c)) {
ss << "'" << c << "'";
} else {
ss << (int)c;
}
return ss.str();
}
template <typename S, typename T> void g(S s, T t){
std::cout << "f<" << typeid(S).name() << "," << typeid(T).name()
<< ">(" << s << "," << prettify(t) << ")\n";
}
template <typename S, typename T> void f(S s = 0, T t = 0){
g<S,T>(s,t);
}
template <typename S> void f(S s = 0, double t = 0) {
g<S,double>(s, t);
}
int main() {
f(1, 'c'); // f<int,char>(1,'c')
f(1); // f<int,double>(1,0)
// f(); // error: T cannot be deduced
f<int>(); // f<int,double>(0,0)
f<int,char>(); // f<int,char>(0,0)
}
The printed output matches the comments for each call to f, and the commented-out call fails to compile as expected.
So I suspect that default template parameters "aren't needed", but probably only in the same sense that default function arguments "aren't needed". As Stroustrup's defect report indicates, the addition of non-deduced parameters was too late for anyone to realise and/or really appreciate that it made defaults useful. So the current situation is in effect based on a version of function templates which was never standard.
On Windows, with all versions of Visual Studio you can convert this error (C4519) to a warning or disable it like so:
#ifdef _MSC_VER
#pragma warning(1 : 4519) // convert error C4519 to warning
// #pragma warning(disable : 4519) // disable error C4519
#endif
See more details here.
What I use is next trick:
Lets say you want to have function like this:
template <typename E, typename ARR_E = MyArray_t<E> > void doStuff(ARR_E array)
{
E one(1);
array.add( one );
}
You will not be allowed, but I do next way:
template <typename T>
struct MyArray_t {
void add(T i)
{
// ...
}
};
template <typename E, typename ARR_E = MyArray_t<E> >
class worker {
public:
/*static - as you wish */ ARR_E* parr_;
void doStuff(); /* do not make this one static also, MSVC complains */
};
template <typename E, typename ARR_E>
void worker<E, ARR_E>::doStuff()
{
E one(1);
parr_->add( one );
}
So this way you may use it like this:
MyArray_t<int> my_array;
worker<int> w;
w.parr_ = &arr;
w.doStuff();
As we can see no need to explicitly set second parameter.
Maybe it will be useful for someone.