Here's a cut down example of what I'm trying to do:
#include <string>
#include <iostream>
#include <type_traits>
template <typename T>
class foo
{
public:
template <typename U>
typename std::enable_if<std::is_same<T, U>::value>::type
bar(const U& t)
{
std::cout << t << "\n";
}
};
template <typename... Args>
class baz
: public foo<Args>...
{
};
int main()
{
baz<double, std::string> b;
b.bar(1.0);
}
This gives me ambiguous function errors:
error: request for member 'bar' is ambiguous
b.bar(1.0);
note: candidates are: template<class U> typename std::enable_if<std::is_same<T, U>::value>::type foo<T>::bar(const U&) [with U = U; T = std::basic_string<char>]
note: template<class U> typename std::enable_if<std::is_same<T, U>::value>::type foo<T>::bar(const U&) [with U = U; T = double]
My questions are twofold:
Why is the inner template U not deduced? I'm supposing that it's due to ordering of template deduction and overload resolution, but can someone explain this?
Is there another way of going about what I'm trying to do?
I think the error message is misleading. The problem is actually name bar is available in multiple base classes and you've not used using directive to bring the names you want into the derived class scope.
Here is one working solution:
template <typename X, typename... Args>
class baz : public foo<X>, public baz<Args...>
{
public:
using foo<X>::bar; //bring the name from the first base
using baz<Args...>::bar; //bring the name from the second base
};
template <typename X>
class baz<X> : public foo<X> //specialization for one argument
{
//no using directive needed, as there is one base only!
};
Complete Demo
The problem has nothing to do with variadic templates, template argument deduction, or the like. It is that member functions of the same name from different base classes don't overload. Minimized example:
struct foo {
void f(int &);
};
struct bar {
void f(const int &);
};
struct foobar : foo, bar { };
int main(){
foobar fb;
int i;
fb.f(i); // clang complains: error: member 'f' found in multiple base classes of different types
}
Since in your code, foo<double> and foo<std::string> are distinct types, and lookup for bar finds a declaration in each, your code is ill-formed.
A possible fix is to write a baz::bar that explicitly dispatches to the appropriate foo::bar:
template <typename... Args>
class baz
: public foo<Args>...
{
public:
template <typename U>
void
bar(const U& t)
{
foo<U>::bar(t);
}
};
You can SFINAE baz::bar on U being one of the types in Args, if desired.
Another possible solution is to use the recursive implementation shown in Nawaz's answer.
Related
I want a member function that more or less does the same thing as this:
template<class T, template<class T> class U>
void f(const U<T>& x)
{
...
}
...but in a template class already parameterized on T:
template<class T>
class A
{
???
// maybe template< template<class T> class U>
// maybe template< class U<T> >
void f(const U<T>& x)
{
...
}
}
This might be doable using type aliases (with using), but this is an older C++98 codebase, so I can't try that route.
You can simply use T inside the member function template when deducing the argument:
template<class T>
struct A
{
template<template<class> class U>
void f(const U<T> & x) {}
};
This constrains the function template f to only accept arguments that are instantiations of a class on T.
A<int> a;
S<int> s1;
a.f(s1); // ok, a and s1 are instantiated over int
a.f(42); // error, 42 is not a U<T>
S<double> s2;
a.f(s2); // error, a is instantiated over int,
// but s2 is instantiated over double
Here's a demo.
So, first consider the following where template parameters are known implicitly from the function arguments:
#include <iostream>
using namespace std;
class A {};
class B {};
template <class T1, class T2>
class C {
T1 a;
T2 b;
};
template <class T1>
class D {
T1 a;
};
template <template<class, class> class TC, class TA, class TB>
void foo(TC<TA, TB> c) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(TD<TA> d){
std::cout << "T<T>" << std::endl;
};
int main() {
C<A,B> c;
D<A> d;
foo(c);
foo(d);
}
And output is as you'd expect:
T<T,T>
T<T>
However, what if I don't have an instance of class C and D so I need to explicitly call the correct overload? How would this be done? i.e., have a main() that consists of:
int main() {
foo<C<A,B> >();
foo<D<A> >();
}
I've experimented with a few overloads of foo() as shown below:
template <template<class, class> class TC>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD>
void foo(){
std::cout << "T<T>" << std::endl;
};
template <template<class, class> class TC, class TA, class TB>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(){
std::cout << "T<T>" << std::endl;
};
However, this (and all permutations I've been able to think of) simply results in a series of errors along the lines of the (abbreviated) output shown below
prog.cpp: In function 'int main()':
prog.cpp:44:18: error: no matching function for call to 'foo()'
foo<C<A,B> >();
^
prog.cpp:44:18: note: candidates are:
prog.cpp:19:6: note: template<template<class, class> class TC> void foo()
void foo() {
^
prog.cpp:19:6: note: template argument deduction/substitution failed:
prog.cpp:24:6: note: template<template<class> class TD> void foo()
void foo(){
^
prog.cpp:24:6: note: template argument deduction/substitution failed:
Is what I'm looking to do even allowable? If so, where am I messing up?
---- EDIT ----
So as apple apple pointed out if my main() is as follows:
int main() {
foo<C, A, B>();
foo<D, A>();
}
I get the output as expected.
However, my real-world case winds up being more complex. I'll expand a bit here. The legacy code has (hundreds) of typedefs defined in headers elsewhere along the lines of:
typedef C<A, B> type_117;
typedef D<A> type_252;
The class I'm working on is templated and is instantiated with one of those typedefs as the templating argument. So something along the lines of:
template <class Type>
class Test
{
public:
Test();
SomeClass mSC;
}
Test::Test()
: mSC(foo<Type>())
{
};
where Test was instantiated as
Test<type_117> aTest;
So I've been trying to figure out how to write foo() for this context. At the point I call foo() within my Test's initializer am I able to "decompose" it to produce the <C,A,B> form? Or have I hit a roadblock and need to rework some of the existing framework?
template<class T>struct tag_t{constexpr tag_t(){}};
template<class T>constexpr tag_t<T> tag{};
these are type tags. They can be passed to functions without an instance of the type.
Template functions will deduce on them.
template <template<class, class> class TC, class TA, class TB>
void foo(tag_t<TC<TA, TB>>) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(tag_t<TD<TA>>){
std::cout << "T<T>" << std::endl;
};
at call site do foo(tag<type_117>) and bob, as they say, is your uncle.
In C++98 (ick):
template<class T>struct tag_t{};
foo(tag_t<type_117>());
You may use partial specialization (and variadic template):
template <class Type>
class Test;
template <template <typename ...> class C, typename ... Ts>
class Test<C<Ts...>>
{
public:
Test() : mSC(foo<C, Ts...>()) {}
SomeClass mSC;
};
Take in count that partial specialization is forbidden for functions; so is difficult to do what do you exactly asked.
The suggestion from apple apple (chenge the calling as foo<C, A, B>() is a good one but, if you want to maintain the original call (foo<C<A, B>>()) you can use the fact that the partial specialization is allowed for structs/classes and create a partial specialization for a functor; something like
template <typename>
struct bar;
template <template<typename, typename> class Tc, typename Ta, typename Tb>
struct bar<Tc<Ta,Tb>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta, Tb>>()" << std::endl; }
};
template <template<typename> class Tc, typename Ta>
struct bar<Tc<Ta>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta>>()" << std::endl; }
};
The problem (?) is that, calling it, you can't call as bar<C<A,B>>() od bar<D<A>>() but you have to add a couple of parentheses:
bar<C<A,B>>()();
bar<D<A>>()();
or
bar<C<A,B>>{}();
bar<D<A>>{}();
I suppose that the functor solution can solve also the problem of the Edit part of your question.
If the added couple of parentheses is a problem, you can (as suggested by Jarod42 (thanks!)) wrap the call in a template function, as follows
template <typename T>
void bar ()
{ bar<T>{}(); }
So you can call the bar<C<A, B>>() function and manage the call in the specialized bar<C<A, B>> struct.
Observe also the solution from Jarod42: depending on your requirements, you could develop only a version of the partial specialization of bar.
-- EDIT --
The OP ask
I'm not that familiar with partial specialization; could you expand a bit on how what I was trying was?
Specialization (partial and full) is a big, big topic.
Just some example, to give an idea.
Given a template class/struct
template <typename X, typename Y>
struct foo
{ };
you can partial specialize it as follows (by example)
template <typename X>
struct foo<X, X>
{ };
when the specialization maintain a template variable, or you can full specialize as follow (by example)
template <>
struct foo<int, long>
{ };
where all template argument are fixed.
Well: with function you can full specialize but not partial specialize.
So you can write a template function
template <typename X, template Y>
void foo ()
{ }
and full specialize it
template <>
void foo<int, long> ()
{ }
but you can't partial specialize it; so you can't write (is an error)
template <typename X>
void foo<X, X> ()
{ }
I've been using code like this for a while (since GCC 4.9/Clang 3.5 at least):
#include <utility>
class foo
{
public:
void bar(int n);
template <typename R,
typename = decltype(std::declval<foo>().bar(*std::begin(std::declval<R>())))>
void bar(const R& range);
};
The point of the second bar() overload is it should be SFINAE'd away unless R is a range type where an overload of bar() exists for its elements. So std::vector<int> would be fine but std::vector<int*> wouldn't, for example.
Unfortunately, since Clang 3.9, that gives this error:
templ.cpp:12:54: error: member access into incomplete type 'foo'
typename = decltype(std::declval<foo>().bar(*std::begin(std::declval<R>())))>
^
templ.cpp:6:7: note: definition of 'foo' is not complete until the closing '}'
class foo
^
1 error generated.
Is there a way to accomplish this that doesn't rely on using an incomplete type from within its own definition?
Maybe you could make foo a default value of additional template parameter:
#include <utility>
class foo
{
public:
void bar(int n);
template <typename R,
typename F = foo,
typename = decltype(std::declval<F>().bar(*std::begin(std::declval<R>())))>
void bar(const R& range);
};
[live demo]
This would delay the check if foo is complete.
The fast and easy way would be to define bar in a base class.
#include <utility>
template<typename child>
struct base {
void bar(int);
};
struct foo : base<foo> {
template<typename R,
typename = decltype(std::declval<base<foo>>().bar(std::begin(std::declval<R>())))>
void bar(const R& range);
};
But this method can be cumbersome.
Alternatively, if you know what type bar need, you can do this:
struct foo {
void bar(int);
template<typename R,
std::enable_if_t<std::is_constructible<int, decltype(*std::begin(std::declval<R>()))>>* = 0>
void bar(const R& range);
};
If bar is limited with a constraint, you could use the very same constraint:
struct foo {
template<typename T, std::enable_if_t<some_contraint<T>::value>* = 0>
void bar(T);
template<typename R,
std::enable_if_t<some_contraint<*std::begin(std::declval<R>())>::value>* = 0>
void bar(const R& range);
};
At last, if you like the last two options, you can encapsulate the range constraint in a type trait:
template<typename, typename = void>
struct is_valid_range : std::false_type {};
template<typename T>
struct is_valid_range<T, std::enable_if_t<some_contraint<*std::begin(std::declval<R>())>::value>> : std::true_type {};
It looks like you're trying to make it so that the overload would not be selected if the function's body wouldn't compile. The trouble is that the compiler needs to make sure that the signature compiles before moving on to the body.
Instead, how about SFINAE'ing based on what you need to be able to do with R more specifically? For example:
template<typename R,
class = decltype(begin(std::declval<const R&>())),
class = decltype(end(std::declval<const R&>()))>
void bar(const R& range);
That way this overload is only selected if you can call begin and end on a type f const R&.
class Foo;
void free_bar(Foo* foo, int n){
(void)foo;
std::cout << n << "\n";
}
class Foo {
public:
template<class X>
void bar(X&& x) {
return free_bar( this, std::forward<X>(x) );
}
};
template <typename R>
auto free_bar(Foo* foo, const R& range)
-> decltype( free_bar( foo, *std::begin(range) ) )
{
for (auto&&x:range)
free_bar(foo, decltype(x)(x));
}
This places the bar into free functions that take a Foo* as their first argument.
The member .bar(X) invokes this free function.
ADL means that it does the right thing(tm) usually.
live example
This is probably a duplicate, but I just can't find one where the OP clearly has the same problem I'm having.
I have a class, and I'm trying to enable operator- only if the class template parameter is not an unsigned type.
#include <type_traits>
template<class T>
struct A {
typename std::enable_if<!std::is_unsigned<T>::value,A>::type operator-() {return {};}
};
int main() {
A<unsigned> a=a;
}
Unfortunately, this produces a compiler error any time I instantiate it with an unsigned type as shown.
main.cpp:5:29: error: no type named 'type' in 'std::enable_if<false, A<unsigned int> >'; 'enable_if' cannot be used to disable this declaration
typename std::enable_if<!std::is_unsigned<T>::value,A>::type operator-() {return {};}
^~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:9:17: note: in instantiation of template class 'A<unsigned int>' requested here
A<unsigned> a=a;
^
Well, I can clearly see that enable_if is not going to work here. One vaguely similar question mentioned I can use inheritance and template specialization to work around this, but... is there really no better way?
I had the same problem once. Turns out there can't be a substitution failure since the default template argument doesn't depend on a template parameter from the function template. You have to have a template argument defaulted to the enclosing template type, like this:
template<typename U = T,
class = typename std::enable_if<!std::is_unsigned<U>::value, U>::type>
A operator-() { return {}; }
A bit long for a comment: You can also use a free function, even for unary operators.
#include <type_traits>
template<class T>
struct A {
};
template<class T>
typename std::enable_if<!std::is_unsigned<T>::value,A<T>>::type
operator-(A<T>) {return {};}
int main() {
A<signed> b;
-b; // ok
A<unsigned> a;
-a; // error
}
This doesn't introduce a member function template for each class template.
Here's how you can befriend it:
template<class T>
class A {
int m;
public:
A(T p) : m(p) {}
template<class U>
friend
typename std::enable_if<!std::is_unsigned<U>::value,A<U>>::type
operator-(A<U>);
};
template<class T>
typename std::enable_if<!std::is_unsigned<T>::value,A<T>>::type
operator-(A<T> p) {return {p.m};}
int main() {
A<signed> b(42);
-b; // ok
A<unsigned> a(42);
//-a; // error
}
You can (should) forward-declare that function template, though.
One possible way is introducing a dummy template parameter:
template<class T>
struct A {
template<
typename D = int,
typename = typename std::enable_if<!std::is_unsigned<T>::value, D>::type
>
A operator-() {return {};}
};
There is a long way using inheritance:
template <class T>
struct A;
template <class T, bool = std::is_unsigned<T>::value>
struct MinusOperator
{
A<T> operator-()
{
A<T>* thisA = static_cast<A<T>*>(this);
// use thisA instead of this to get access to members of A<T>
}
};
template <class T>
struct MinusOperator<T, true> {};
template <class T>
struct A : MinusOperator<T>
{
friend struct MinusOperator<T>;
};
This compiles:
template <class T>
class Bar {};
template<class T, class Dummy=void>
class Foo;
template<class T>
class Foo <T, typename std::enable_if<
std::is_base_of<Bar<T>, T>::value
>::type> {
public:
//THIS CHANGES IN THE 2ND SNIPPET
void test () const {
std::cout << "test";
}
};
class Cat : Bar<Cat> {};
int main () {
Foo<Cat> foo;
foo.test();
return 0;
}
This errors:
template <class T>
class Bar {};
template<class T, class Dummy=void>
class Foo;
template<class T>
class Foo <T, typename std::enable_if<
std::is_base_of<Bar<T>, T>::value
>::type> {
public:
//THIS CHANGED!
void test () const;
};
//THIS WAS ADDED SINCE THE 1ST SNIPPET!
template<class T>
void Foo<T>::test () const {
std::cout << "test";
} //error C2039: 'test' : is not a member of 'Foo<T>'
class Cat : Bar<Cat> {};
int main () {
Foo<Cat> foo;
foo.test();
return 0;
}
I have marked the differences. Why does it error in the 2nd code snippet? How do I keep declaration and definition separate while avoiding the error?
I'm guessing it's got something to do with this:
"template
void Foo::test () const"
Like, this is the wrong way to tell the compiler that the method test() const is a method of template class template class Foo , T>::value >::type>
I've, of course, looked it up on Google and StackOverflow but it seems that, whenever this error pops up for templates, it's a different reason every time. (Probably because a lot of things can cause the C2039 error.)
Also, could a mod. or someone help me add the C2039 tag to this post? It says I need a min. of 1500 rep. to add that tag.
-- Rambling --
It also be noted that it's been a while since I've used C++; and even longer since I've used templates. I know this might be a weird way to use templates but I can assure you I have a valid reason!
An example of out-of-class member declaration for a partially specialized class template is given in 14.5.4.3/1 (C++03). And this is what it looks like
// primary template
template<class T, int I> struct A {
void f();
};
// class template partial specialization
template<class T> struct A<T,2> {
void g();
};
// member of class template partial specialization
template<class T> void A<T,2>::g() { }
As you can see, you have to specify specialized arguments in the out-of-class member definition.
In your case it should be
template<class T>
void Foo<T, typename std::enable_if<
std::is_base_of<Bar<T>, T>::value>::type>::test () const {
std::cout << "test";
}