Template alias in template function - c++

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.

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
}

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;
}

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.

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;
}

Related

Using template type as argument to std::invoke

Consider this code:
using namespace std;
struct FS
{
void print() { cout << "p\n"; }
int s;
};
template <typename T, typename F>
void myInvoke(T& t, F f)
{
invoke(f, t) = 10;
}
int main(int, char**)
{
FS fs;
myInvoke(fs, &FS::s);
cout << fs.s << "\n";
}
Is there anyway to avoid the runtime cost of passing the class member pointer to myInvoke?
I can of course do:
template <typename T>
void myInvoke(T& t)
{
invoke(&T::s, t) = 10;
}
// then call with
myInvoke(fs);
What I'd like to do:
template <typename T, typename P, P FS::* f>
void myInvoke(T& t)
{
invoke(f, t) = 30;
}
// call with:
myInvoke<FS, int ,&FS::s>(fs);
But without the typename P. Is there any way to make the call more concise so it can be called with:
myInvoke<FS, &FS::s>(fs);
I know this is a bit arcane, but it'd be really nice to be as concise as possible. Especially when you have widely used library functions.
EDIT:
Link to sandbox above code: https://godbolt.org/z/z4cGdPd3r
It seems you are looking for deduced Non-type template parameter (with auto) (C++17):
template <auto F, typename T>
void myInvoke(T& t)
{
invoke(F, t) = 10;
}
with usage:
myInvoke<&FS::s>(fs);
Demo

Overloading function with multiple template definitions not possible?

I tried this:
template<typename P, typename = std::enable_if_t<std::is_arithmetic<P>::value>>
void f(std::vector<P>* a) {
// body for arithmetic P
}
template<typename P, typename = std::enable_if_t<std::is_class<P>::value>>
void f(std::vector<P>* a) {
// body for class P
}
I thought it would overload f as the conditions are mutually exclusive, but found that it doesn't compile: "function template has already been defined".
What to do instead, if I want the function body of f(std::vector<P>*) to depend on whether P is arithmetic?
The std::enable_if documentation on cppreference.com says:
A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal.
The examples on that same page show a similar situation as yours, and solve it by changing the template on one of the overloads, while maintaining the same signature for the functions themselves:
// #4, enabled via a template parameter
template<class T,
typename std::enable_if<
!std::is_trivially_destructible<T>{} &&
(std::is_class<T>{} || std::is_union<T>{}),
int>::type = 0>
void destroy(T* t)
{
std::cout << "destroying non-trivially destructible T\n";
t->~T();
}
// #5, enabled via a template parameter
template<class T,
typename = std::enable_if_t<std::is_array<T>::value> >
void destroy(T* t) // note, function signature is unmodified
{
for(std::size_t i = 0; i < std::extent<T>::value; ++i) {
destroy((*t)[i]);
}
}
/*
template<class T,
typename = std::enable_if_t<std::is_void<T>::value> >
void destroy(T* t){} // error: has the same signature with #5
*/
So, you can do something similar in your code:
template<typename P, std::enable_if_t<std::is_arithmetic<P>::value, int> = 0>
void f(std::vector<P>* a)
{
// body for arithmetic P
}
template<typename P, typename = std::enable_if_t<std::is_class<P>::value>>
void f(std::vector<P>* a)
{
// body for class P
}
Live Demo
Use tag dispatch, like this or similar:
void f_helper(std::vector<P>* a, std::true_type) {
/* implementation for arithmetic type P */
}
void f_helper(std::vector<P>* a, std::false_type) {
/* implementation for class type P */
}
void f(std::vector<P>* a) {
return f_helper(a, std::is_arithmetic<P>{});
}

Passing a type specifier to a template function

I am trying to replace a Macro in the form of
#define FOO(object, typeSpecifier) object.f<typeSpecifier>()
How can i write an equivalent template function that takes a type specifier to call object.f<typeSpecifier>() with?
I.e. pass a custom type with specifier Mytype and an object object to f like f(object, MyType)
Edit there were some misleading mistakes in simplified code before the answers were made. I.e. the macro had the same name of the function it replaces, this was wrong
Functions cannot take type as parameter, so you cannot do with function:
f(foo, int); // Not possible
You can wrap the type:
template <typename> struct tag{};
f(foo, tag<int>{});
but then you have to change the calling code.
So you have to keep the macro if you don't want to change the calling sites.
If you can change call sites to f<int>(foo);, then you may use:
template <typename T, typename Object>
decltype(auto) f(Object&& object)
{
return std::forward<Object>(object).template <T>()
}
A zero-overhead way would be to use tag dispatch:
#include <iostream>
template<class Type> struct tag {};
template<class Object, class Tag>
decltype(auto) f(Object&& o, tag<Tag>)
{
return o.template f<Tag>();
}
struct X {
template<class T> auto f() {
return T(0);
}
};
template<> auto X::f<int>() {
std::cout << "an int" << std::endl;
return 0;
}
template<> auto X::f<double>() {
std::cout << "a double" << std::endl;
return 0;
}
int main()
{
X x;
f(x, tag<int>());
f(x, tag<double>());
}
You can rely on template argument deduction like:
template<typename T, typename U>
void f(T& object, const U& typeSpecifier) {
object.template f<U>();
}
In this case you can call the f function e.g. as follows:
f(foo, std::string{});
As the comments below point out, my example works only for default constructable types, therefore using a helper type as shown in the accepted answer is a better approach:
template<typename>
struct type {
};
template<typename T, typename U>
void f(T& object, type<U>) {
object.template f<U>();
}
Usage with c++98:
int main() {
MyType foo;
f(foo, type<std::string>());
}

Achieve functor overloading through composition

Given some existing functors:
struct incr {
int operator()(int x) const { return x + 1; }
};
struct rep_str {
std::string operator()(const std::string& s) const { return s + s; }
};
I'm wondering if it's possible to achieve something like this:
auto f = overload<incr, rep_str>();
f(1); // returns 2
f("hello"); // returns "hellohello"
Multiple overloads may look like:
auto f = overload<fa, fb, fc, ...>();
// or...
auto g = overload<fa, overload<fb, overload<fc, ...>>>();
I'm thinking maybe use SFINAE with std::result_of_t or something like that, but haven't figured out how.
You don't need anything too fancy: just inherit from all the arguments and use using-declarations to bring in operator() from the base classes. However, in the variadic case, you can't have a pack expansion in a using-declaration, so you have to use a recursive approach, like so:
template <class... Ts>
struct overload {}; // only used for empty pack
template <class T>
struct overload<T> : private T {
using T::operator();
};
template <class T1, class T2, class... Ts>
struct overload<T1, T2, Ts...> : private T1, overload<T2, Ts...> {
using T1::operator();
using overload<T2, Ts...>::operator();
};
Brian's answer is better, IMHO, but since I worked on it, here's mine:
#include <type_traits>
#include <utility>
template <typename... Fns>
struct overload;
template <typename Fn, typename... Fns>
struct overload<Fn, Fns...>
{
template <typename... T>
std::result_of_t<Fn(T...)> operator()(T && ... args) const {
return Fn()(std::forward<T>(args)...);
}
using next = overload<Fns...>;
template <typename... T>
std::result_of_t<next(T...)> operator()(T && ... args) const {
return next()(std::forward<T>(args)...);
}
};
this can be done using template specialization:
#include <string>
#include <iostream>
template <typename...Args>
struct overload{
};
template <> struct overload<int>{
int operator()(int x) const { return x + 1; }
};
template <> struct overload< std::string>{
std::string operator()(const std::string& s) const { return s + s; }
};
template <typename...Args >
auto f(Args...arg){
overload<Args...> func;
return func(arg...);
}
int main()
{
std::cout << f(3) << std::endl << f(std::string("Hello"));
}
Note: two answers by #Brian and #md5i more general and elegant and perfect and better than this.

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.