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.
}
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.
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);
}
Related
I have some classes which need to define a template which can be used in generic code parts as type later.
In real world code the forwarded templates have a lot more parameters and it is not really nice to read the code.
Q: Is it possible to define the template in some syntax instead of writing it as alias template as given in the following example? I simple would avoid repeating of all the template parameters two times of each alias declaration.
The real world template also have some non type template parameters so simply using <PARMS...> will not work.
Example:
#include <iostream>
template < typename T>
struct A
{
static void Do(T t) { std::cout << "A " << t << std::endl;}
};
template < typename T>
struct B
{
static void Do(T t) { std::cout << "B " << t << std::endl;}
};
struct UseA
{
// using the alias template works as expected, but...
template < typename T>
using USE = A<T>;
// is there any chance to write something like:
// using USE = A;
// to simply avoid replication of template parameters?
};
struct UseB
{
template < typename T>
using USE = B<T>;
};
int main()
{
UseA::USE<int>::Do(1);
UseB::USE<std::string>::Do("Hallo");
}
What you are asking cannot be done. You always have to define the whole type list. The reason is, that one could have default overloads for the same type. For example, in the following A<int, 3>, A<int> and A<> are all valid. The compiler does not know which one you want:
template <class T, int Value = 42>
struct A {};
auto test() {
auto a = A<int, 3>{};
auto b = A<int>{};
auto c = A<>{};
}
If you don't want to write the type lists, I would recommend you to switch to templatizing more of your classes, so they don't need to know about the implementation details. Like:
#include <iostream>
template < typename T>
struct A
{
static void Do(T t) { std::cout << "A " << t << std::endl;}
};
template < typename T>
struct B
{
static void Do(T t) { std::cout << "B " << t << std::endl;}
};
template < typename T>
struct Use
{
using USE = T;
};
int main()
{
Use<A<int>>::USE::Do(1);
Use<B<std::string>>::USE::Do("Hallo");
}
Or alternatively, use containers for your non template type values:
#include <iostream>
template < int Value >
struct INT
{
static constexpr int value = Value;
};
template < bool Value >
struct BOOL
{
static constexpr bool value = Value;
};
template < typename T, typename Value >
struct A
{
static void Do(T t) { std::cout << "A " << t << Value::value << std::endl;}
};
template < typename T, typename Value>
struct B
{
static void Do(T t) { if (Value::value) std::cout << "B " << t << std::endl;}
};
template <template<typename...> class T, typename ...Param>
using USE = T<Param...>;
int main()
{
USE<A, int, INT<42>>::Do(1);
USE<B, std::string, BOOL<true>>::Do("Hallo");
}
I tried to implement template function specialization. You can run my tiny code in this fiddle. You can also see it below
#include <iostream>
#include <vector>
#include <list>
template <typename T>
struct is_vector {
static const bool value = false;
};
template <typename T>
struct is_vector<std::vector<T>> {
static const bool value = true;
using type = std::vector<T>;
};
template <typename T>
struct is_list {
static const bool value = false;
};
template <typename T>
struct is_list<std::list<T>> {
static const bool value = true;
using type = std::list<T>;
};
template<typename T, class = typename std::enable_if<is_list<T>::value>::type>
void foo(T t) {
std::cout << "is list" << std::endl;
}
/*
template<typename T, class = typename std::enable_if<is_vector<T>::value>::type>
void foo(T t) {
std::cout << "is vector" << std::endl;
}
*/
//The above code will cause an error, if we uncomment it
int main()
{
foo(std::list<int>{});
return 0;
}
In this code, I have several lines commented:
template<typename T, class = typename std::enable_if<is_vector<T>::value>::type>
void foo(T t) {
std::cout << "is vector" << std::endl;
}
If I uncomment it, I get "redifinition" error. I'm not sure how to fix it.
If I uncomment it, I get "redifinition" error. I'm not sure how to fix it.
The reason is quite simple: default values for template type arguments are not a part of a function signature. It means that you have the same template defined two times.
You might move SFINAE part in to the function return type, as it is suggested by other answers, or change the code to:
template<typename T, std::enable_if_t<is_list<T>::value, int> = 0>
void foo(T t) {
std::cout << "is list" << std::endl;
}
template<typename T, std::enable_if_t<is_vector<T>::value, int> = 1>
void foo(T t) {
std::cout << "is vector" << std::endl;
}
You can do this instead.
template<typename T>
typename std::enable_if<is_list<T>::value>::type foo(T t) {
std::cout << "is list" << std::endl;
}
template<typename T>
typename std::enable_if<is_vector<T>::value>::type foo(T t) {
std::cout << "is vector" << std::endl;
}
Not sure if this is what you are after, but you could just check if either list or vector is a matching type:
template<typename T, class = typename std::enable_if<is_list<T>::value || is_vector<T>::value>::type>
void foo(T t) {
std::cout << "is list" << std::endl;
}
Updated fiddle: https://godbolt.org/g/oD3o9q
Update (for C++14):
template<typename T, class = std::enable_if_t<is_list<T>::value || is_vector<T>::value>>
void foo(T t) {
std::cout << "is list" << std::endl;
}
Is the following program compliant C++11? If so, do you know of a specific MSVC bug that triggers it? and/or a possible work-around?
#include <iostream>
struct A {};
struct B {};
constexpr A aaa = {};
constexpr B bbb = {};
template <typename T>
void foo(T, decltype(aaa)) { std::cout << "a"; }
template <typename T>
void foo(T, decltype(bbb)) { std::cout << "b"; }
// ^ C2995 'void foo(T,unknown-type)': function template has already been defined
int main()
{
foo(0, aaa);
foo(0, bbb);
}
If the actual types are substituted for decltype then it works, but in practice these types are too complicated to reproduce and I'd prefer not to have aliases for them.
Works for me (VS 2015 / v140) with the following minor modification:
#include <iostream>
struct A {};
struct B {};
constexpr A aaa = {};
constexpr B bbb = {};
using A_type = decltype(aaa);
using B_type = decltype(bbb);
template <typename T>
void foo(T, A_type) { std::cout << "a"; }
template <typename T>
void foo(T, B_type) { std::cout << "b"; }
int main()
{
foo(0, aaa);
foo(0, bbb);
}
But this variant yields the same error (not sure what to make of it):
template <typename T>
struct TypeWrapper {
using type = T;
};
template <typename T>
void foo(T, typename TypeWrapper<decltype(aaa)>::type) { std::cout << "a"; }
template <typename T>
void foo(T, typename TypeWrapper<decltype(bbb)>::type) { std::cout << "b"; }
Suppose I've written:
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
void foo() { std::cout << "T is integral." << std::endl; }
template <typename T>
void foo() { std::cout << "Any T." << std::endl; }
int main() { foo<short>(); }
When I compile this, I get an error about the ambiguity of the call (and no error if, say, I replace short with float). How should I fix this code so that I get the upper version for integral types and lower version otherwise?
Bonus points if your suggestion scales to the case of multiple specialized versions of foo() in addition to the general one.
I like Xeo's approach for this problem. Let's do some tag dispatch with a fallback. Create a chooser struct that inherits from itself all the way down:
template <int I>
struct choice : choice<I + 1> { };
template <> struct choice<10> { }; // just stop somewhere
So choice<x> is convertible to choice<y> for x < y, which means that choice<0> is the best choice. Now, you need a last case:
struct otherwise{ otherwise(...) { } };
With that machinery, we can forward our main function template with an extra argument:
template <class T> void foo() { foo_impl<T>(choice<0>{}); }
And then make your top choice integral and your worst-case option... anything:
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
void foo_impl(choice<0> ) {
std::cout << "T is integral." << std::endl;
}
template <typename T>
void foo_impl(otherwise ) {
std::cout << "Any T." << std::endl;
}
This makes it very easy to add more options in the middle. Just add an overload for choice<1> or choice<2> or whatever. No need for disjoint conditions either. The preferential overload resolution for choice<x> takes care of that.
Even better if you additionally pass in the T as an argument, because overloading is way better than specializing:
template <class T> struct tag {};
template <class T> void foo() { foo_impl(tag<T>{}, choice<0>{}); }
And then you can go wild:
// special 1st choice for just int
void foo_impl(tag<int>, choice<0> );
// backup 1st choice for any integral
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
void foo_impl(tag<T>, choice<0> );
// 2nd option for floats
template <class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
void foo_impl(tag<T>, choice<1> );
// 3rd option for some other type trait
template <class T, class = std::enable_if_t<whatever<T>::value>>
void foo_impl(tag<T>, choice<2> );
// fallback
template <class T>
void foo_impl(tag<T>, otherwise );
One more option using tag dispatch (C++11):
#include <iostream>
void foo_impl(std::false_type) {
std::cout << "Any T." << std::endl;
}
void foo_impl(std::true_type) {
std::cout << "T is integral." << std::endl;
}
template <typename T>
void foo() {
foo_impl(std::is_integral<typename std::remove_reference<T>::type>());
//foo_impl(std::is_integral<typename std::remove_reference_t<T>>()); // C++14
}
int main() {
foo<short>(); // --> T is integral.
foo<short&>(); // --> T is integral.
foo<float>(); // --> Any T.
}
Borrowed from Scott Meyers Effective Modern C++ item 27.
One way:
template <typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
void foo() { std::cout << "T is integral." << std::endl; }
template <typename T, typename std::enable_if_t<not std::is_integral<T>::value>* = nullptr>
void foo() { std::cout << "Any T." << std::endl; }
Another way is to defer to a template function object:
template<class T, typename = void>
struct foo_impl
{
void operator()() const {
std::cout << "Any T." << std::endl;
}
};
template<class T>
struct foo_impl<T, std::enable_if_t<std::is_integral<T>::value>>
{
void operator()() const {
std::cout << "T is integral." << std::endl;
}
};
template<class T>
void foo() {
return foo_impl<T>()();
}
One way to do this is:
template <typename T>
std::enable_if_t<std::is_integral<T>::value, void> foo () {
std::cout << "integral version" << std::endl;
}
template <typename T>
std::enable_if_t<!std::is_integral<T>::value, void> foo () {
std::cout << "general version" << std::endl;
}
with usage:
foo<int> ();
foo<double> ();
struct X {};
foo<X> ();
output is:
integral version
general version
general version
AFAIK, sfinae is applicable to function params so try to add parameter of dependent type with default value
template <typename T>
void foo(typename std::enable_if_t<std::is_integral<T>::value>* = 0)
{ std::cout << "T is integral." << std::endl; }
template <typename T>
void foo(typename std::enable_if_t<!std::is_integral<T>::value>* = 0)
{ std::cout << "Any T." << std::endl; }
I want to create an overloaded template, that runs a function Foo() if a class contains it, else it does nothing.
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()" << std::endl;
// Modify u
}
};
class B
{
// Does not contain Foo()
};
I've been trying to run it as such
template <typename T, typename U>
decltype(std::declval<T>().Foo()) TriggerFoo(T* t, U& u)
{
t->Foo(u);
}
template <typename T, typename U>
void TriggerFoo(T* t, U& u)
{
std::cout << "Does not have Foo()" << std::endl;
}
int main()
{
A a;
B b;
U u; // Some type
TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()".
return 0;
}
At the moment, both classes are passed to the "Does not have Foo()" instantiation. It compiles, but obviously it doesn't work, and it is most probably because I don't understand declval well enough. I have also tried with non-template functions and it still does not work.
Any help will be greatly appreciated.
There were two basic issues with your approach:
decltype(std::declval<T>().Foo())
This will never be succesfully resolved, because the Foo() in question will always take a parameter. This part should be:
decltype(std::declval<T>().Foo(std::declval<U &>()))
But now you will run into a different problem: when the class implements Foo(), the template resolution will become ambiguous. Either template function can be used.
So, you need another level of indirection, and templates of different priorities:
#include <iostream>
#include <type_traits>
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()" << std::endl;
// Modify u
}
};
class B
{
// Does not contain Foo()
};
template <typename T, typename U, typename Z=decltype(std::declval<T>().Foo(std::declval<U &>()))>
void DoTriggerFoo(T* t, U& u, int dummy)
{
t->Foo(u);
}
template <typename T, typename U>
void DoTriggerFoo(T* t, U& u, ...)
{
std::cout << "Does not have Foo()" << std::endl;
}
template <typename T, typename U>
void TriggerFoo(T *t, U &u)
{
DoTriggerFoo(t, u, 0);
}
class U {};
int main()
{
A a;
B b;
U u; // Some type
TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()".
return 0;
}
Results with gcc 5.3:
$ ./t
Has Foo()
Does not have Foo()
P.S.:
std::declval<T &>().Foo(std::declval<U &>())
It's possible that this will work better, with your actual classes.
Extension to Sam's answer, if you aren't using pointers you can simplify the code further which makes it look a bit neater.
#include <iostream>
#include <type_traits>
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()\n";
}
};
class B
{
// Does not contain Foo()
};
template <
typename T,
typename U,
typename Z=decltype(std::declval<T>().Foo(std::declval<U&>()))>
void TriggerFoo(T& t, U& u)
{
t.Foo(u);
}
template <typename... T>
void TriggerFoo(const T&...)
{
std::cout << "Does not have Foo()\n";
}
class U {};
int main()
{
A a;
B b;
U u;
TriggerFoo<A, U>(a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(b, u); // Prints "Does not have Foo()".
return 0;
}