I have classes foo_impl, bar_impl deriving from derived classes foo_derived, bar_derived, and a function that takes in a templated template-parameter:
#include <iostream>
template <typename T>
struct foo_base
{
T a;
};
template <typename T>
struct foo_derived: public foo_base<T>
{
};
struct foo_impl: public foo_derived<int>
{
};
template <typename T>
struct bar_base
{
T a;
};
template <typename T>
struct bar_derived : public bar_base<T>
{
};
struct bar_impl : public bar_derived<int>
{
};
template <typename T, template <class> typename Base>
void useBase(const Base<T>& Arg)
{
std::cout << Arg.a << std::endl;
}
int main()
{
foo_impl foo;
bar_impl bar;
useBase(foo); // ‘const Base<T>’ is an ambiguous base class of ‘foo_impl’
useBase(bar); // ‘const Base<T>’ is an ambiguous base class of ‘bar_impl’
}
Is it possible to specify that I want foo_base and bar_base to be the only types that can be passed to useBase(.)?
Edit: I tried introducing a concept in order to constrain the accepted types, but the compiler is still not happy.
template <typename T, template <class> typename Base>
concept is_base = !std::is_same<std::is_same<Base<T>, foo_base<T>>, std::is_same<Base<T>, bar_base<T>>>::value;
template <typename T, template <class> typename Base>
void useBase(const Base<T>& Arg) requires is_base<T, Base>
{
std::cout << Arg.a << std::endl;
}
As state in comment, overloading might be a possibility:
template <typename T, template <class> typename Base>
void useBaseImpl(const Base<T>& Arg)
{
std::cout << Arg.a << std::endl;
}
template <typename T>
void useBase(const foo_base<T>& arg)
{
useBaseImpl(arg);
}
template <typename T>
void useBase(const bar_base<T>& arg)
{
useBaseImpl(arg);
}
Related
I have class like this:
template<typename T>
MyClass{
//myFunc();
}
I want to create myFunc method that return numeric value if class template is numeric and return nothing (void) when class template is not numeric.
For now, I got sth like this:
template<typename T>
MyClass{
template <typename returnT>
returnT myFunc();
}
template <typename T>
template <typename returnT>
typename std::enable_if<std::is_arithmetic<T>::value>
T MyClass<T>::myFunc()
{
return T::value;
}
template <typename T>
template <typename returnT>
typename std::enable_if<!std::is_arithmetic<T>::value>
void MyClass::myFunc()
{
//do sth
}
of course, that doesn't work. Is that a good idea to solve this problem this way? What is "smart" and working solution?
As an alternative to the constexpr if solution already supplied, here is your initial idea in it's working form.
#include <type_traits>
#include <iostream>
template<typename T>
struct MyClass{
template <typename returnT = T, std::enable_if_t<std::is_arithmetic_v<returnT>, bool> = true>
T myFunc();
template <typename returnT = T, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool> = true>
void myFunc();
};
template <typename T>
template <typename returnT, std::enable_if_t<std::is_arithmetic_v<returnT>, bool>>
T MyClass<T>::myFunc()
{
std::cout << "yo\n";
return T{};
}
template <typename T>
template <typename returnT, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool>>
void MyClass<T>::myFunc()
{
std::cout << "yay\n";
}
int main() {
MyClass<int> m;
MyClass<std::string> n;
m.myFunc();
n.myFunc();
}
The simplest way I can think of would be to just use if constexpr:
template <typename T>
class MyClass
{
auto myFunc()
{
if constexpr (std::is_arithmetic_v<T>)
{
return T{};
}
else
{
// do smth
}
}
};
If you can't use C++17, you will have to revert to some SFINAE-based approach. What that would best look like exactly depends a lot on what the actual signatures involved should be. But, for example, you could provide a partial class template specialization for the case of an arithmetic type:
template <typename T, typename = void>
class MyClass
{
void myFunc()
{
// do smth
}
};
template <typename T>
class MyClass<T, std::enable_if_t<std::is_arithmetic<T>::value>>
{
T myFunc()
{
return {};
}
};
Note that an arithmetic type cannot be a class type or enum, so I'm not sure what T::value was trying to achieve in your example code for the case of T being an arithmetic type…
I would create a helper template class to select the return type, and a helper function that uses overloading to perform the right behavior.
template <typename, bool> struct RType;
template <typename T> struct RType<T, false> { typedef void type; };
template <typename T> struct RType<T, true> { typedef T type; };
template<typename T>
class MyClass{
typedef RType<T, std::is_arithmetic<T>::value> R;
void myFuncT(RType<T, false>) {}
T myFuncT(RType<T, true>) { return 0; }
public:
typename R::type myFunc() { return myFuncT(R()); }
};
I'm trying to specialize member functions of a template class based on the type of template. In particular I'd like to have specializations based on polymorphic types. I've been struggling with the syntax. Here is my try which obviously produces the error: two or more data types in declaration of doSomething()
class Base {};
class Derived : public Base {};
template<typename T>
class MyClass
{
public:
void doSomething();
};
template<>
template<typename T>
typename std::enable_if<std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething()
{
// Do something with Derived type
}
template<>
template<typename T>
typename std::enable_if<std::is_base_of<Base, T>::value &&
!std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething()
{
// So something with Base type
}
template<>
template<typename T>
typename std::enable_if<!std::is_base_of<Derived, T>::value>::type
void MyClass<T>::doSomething()
{
// Do something with all other types
}
Compilation gives..
error: two or more data types in declaration of 'doSomething'
BTW, I did get the following to compile, but the specialization did not work as expected at runtime. Base and derived types end up going through the non-specialized version of doSomething().
class Base {};
class Derived : public base {};
template<typename T>
class MyClass
{
public:
void doSomething()
{
// Do something for non-specialized types
}
};
template<>
void MyClass<Derived>::doSomething()
{
// Do something with Derived type
}
template<>
void MyClass<Base>::doSomething()
{
// So something with Base type
}
What would be the correct syntax?
You cannot specialize doSomething simply because it's not a template. MyClass is a template and you can specialize the class, each specialization having one doSomething. If that's not what you want then you need to make doSomething template overloads and, for the SFINAE to work, the SFINAE check must be done on the doSomething template parameter, not on the MyClass parameter. Lastly your checks are wrong.
So here is my version:
template<class T> struct MyClass
{
template <class U = T>
auto foo() -> std::enable_if_t<std::is_base_of_v<Base, U>
&& !std::is_base_of_v<Derived, U>>
{
foo_base();
}
template <class U = T>
auto foo() -> std::enable_if_t<std::is_base_of_v<Derived, U>>
{
foo_derived();
}
template <class U = T>
auto foo() -> std::enable_if_t<!std::is_base_of_v<Base, U>>
{
foo_else();
}
};
And here is a battery of tests:
class Base {};
class Derived : public Base {};
class A : Base {};
class B : Derived {};
class X {};
auto test()
{
MyClass<Base>{}.foo(); // foo_base
MyClass<Derived>{}.foo(); // foo_derived
MyClass<A>{}.foo(); // foo_base
MyClass<B>{}.foo(); // foo_derived
MyClass<X>{}.foo(); // foo_else
}
And of course I must mention the C++17 clean solution:
template<class T> struct MyClass
{
auto foo()
{
if constexpr (std::is_base_of_v<Derived, T>)
foo_derived();
else if constexpr (std::is_base_of_v<Base, T>)
foo_base();
else
foo_else();
}
};
Another possible solution pass through a ForFoo template class, that define a foo() method, with a couple of specializations for Base only and Derived classes. So MyClass<T> can inherit from ForFoo<T>.
I mean... if you define a ForFoo set of template classes as follows
template <typename T, typename = void>
struct ForFoo
{ void foo () { std::cout << "other type" << std::endl; } };
template <typename T>
struct ForFoo<T,
typename std::enable_if<std::is_base_of<Base, T>::value
&& ! std::is_base_of<Derived, T>::value>::type>
{ void foo () { std::cout << "Base type" << std::endl; } };
template <typename T>
struct ForFoo<T,
typename std::enable_if<std::is_base_of<Derived, T>::value>::type>
{ void foo () { std::cout << "Derived type" << std::endl; } };
MyClass simply become
template <typename T>
struct MyClass : public ForFoo<T>
{ };
The following is a full working C++11 example
#include <iostream>
#include <type_traits>
class Base {};
class Derived : public Base {};
class A : Base {};
class B : Derived {};
class X {};
template <typename T, typename = void>
struct ForFoo
{ void foo () { std::cout << "other type" << std::endl; } };
template <typename T>
struct ForFoo<T,
typename std::enable_if<std::is_base_of<Base, T>::value
&& ! std::is_base_of<Derived, T>::value>::type>
{ void foo () { std::cout << "Base type" << std::endl; } };
template <typename T>
struct ForFoo<T,
typename std::enable_if<std::is_base_of<Derived, T>::value>::type>
{ void foo () { std::cout << "Derived type" << std::endl; } };
template <typename T>
struct MyClass : public ForFoo<T>
{ };
int main ()
{
MyClass<Base>{}.foo(); // Base
MyClass<Derived>{}.foo(); // Derived
MyClass<A>{}.foo(); // Base
MyClass<B>{}.foo(); // Derived
MyClass<X>{}.foo(); // other
}
I want to determine the underlying template of a template parameter by using a combination of a template alias and template specializations. The follwing code compiles fine on gcc 4.8, 6.2.1 but not on clang 3.5, 3.8.
#include <iostream>
template <typename T> struct First {};
template <typename T> struct Second {};
template <template <typename> class F, typename T> struct Foo {};
template <typename T> struct Foo<First, T>
{
void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
template <typename T> struct Foo<Second, T>
{
void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
template <typename F, typename T> struct Resolution {};
template <typename T> struct Resolution<First<T>, T>
{
template <typename P> using type = First<P>;
};
template <typename T> struct Resolution<Second<T>, T>
{
template <typename P> using type = Second<P>;
};
int main()
{
Foo<Resolution<First<int>, int>::type, float> my_foo;
my_foo.f(); // main.cpp:34:12: error: no member named 'f' in 'Foo<Resolution<First<int>, int>::type, float>'
return 0;
}
Which behavior is standard conformant?
Answer: This is a know bug in the C++ Standard Core Language , as described by T.C. in the comments . http://wg21.link/cwg1286
I have two classes class A and class B both of them are template classes for a member function in A I want it to act in a special way when the type of A is B
and in a normal way for any other types I don't know how to do this ?
template <class B>
class B
{
private:
T m;
public:
...... any member functions
}
template <class T>
class A
{
private:
T var;
public:
void doSomething();
};
template <class T>
void A<T>::doSomething(){...........//implementation}
template <class T>
void A<B<T>>::doSomething(){................//different implementation}
You can specialize A this way:
template <class T>
class A<B<T>> {
// ...
};
This is an instance of partial template specialization.
If you refuse to specialize the entire class, you can defer the work from A<T>::doSomething() to a function doSomethingForA<T>(A &) that would be partially specialized, and that would possibly be friend of A<T>.
Hope this solves your problem:
#include <iostream>
template <typename T>
struct B {};
template <typename T> struct A;
template <typename T>
void doSomething(T&) { std::cout << "General\n"; }
template <typename T>
void doSomething(A<B<T>>&) { std::cout << "Special\n"; }
template <typename T>
struct A {
void doSomething() {
::doSomething(*this);
}
};
int main()
{
A<int> general;
A<B<int>> special;
general.doSomething();
special.doSomething();
}
I'd appreciate help specializing the method doIt() in the following bit of code for classes that share a common base class, as shown below
#include <iostream>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
struct BarBase {};
struct Bar: BarBase {};
struct FooBase {};
struct Foo: FooBase {};
template <typename T>
struct Task
{
// I'd like to specialize this method for classes with a common base class
void doIt();
};
// my attempt (does not compile)
template <typename T>
typename boost::enable_if<boost::is_base_of<FooBase, T> >::value
doIt() {
std::cout << "Type is derived from FooBase\n";
}
int main()
{
Task<Foo> f;
f.doIt();
}
You can't specialise a template class member. You can specialise a class, and every specialisation is a complete separate class that inherits nothing from the unspecialised template (it may or may not have all or some of the members of the unspecialised class).
What you can also do is have a template member function in a template class, and specialise that. So you can do this:
template <typename T>
struct Task
{
void doIt() { doItPriv<T>(); }
private:
template<typename T1>
void doItPriv();
};
and then specialise doItPriv.
According to this answer,
SFINAE only works if substitution in argument deduction of a template
argument makes the construct ill-formed.
That is why you cannot do smth like that:
template <typename T>
struct Task
{
typename std::enable_if<std::is_base_of<FooBase, T>::value>::type doIt() {
std::cout << "Type is derived from FooBase\n";
}
typename std::enable_if<std::is_base_of<FooBase, T>::value == false>::type doIt()
{
}
};
Here doIt() isn't template, so no any deduction.
But you can do the following:
template <typename T1>
struct Task
{
template <typename T>
typename std::enable_if<std::is_base_of<FooBase, T>::value>::type doIt_() {
std::cout << "Type is derived from FooBase\n";
}
template <typename T>
typename std::enable_if<std::is_base_of<FooBase, T>::value == false>::type doIt_()
{
}
void doIt()
{
doIt_<T1>();
}
};