Could I use SFINAE (or another technique) for using declaration while private deriving from template class?
For better understanding see code below:
#include <iostream>
struct S1 {
void f() { std::cout << "S1::f\n"; }
};
struct S2 {
void f() { std::cout << "S2::f\n"; }
void g() { std::cout << "S2::g\n"; }
};
template <class T>
struct D : private T {
using T::f;
// using T::g; // need this only if T provides g() function
};
int main() {
D<S1>().f(); // ok. Prints 'S1::f'
D<S2>().f(); // ok. Prints 'S2::f'
D<S2>().g(); // fail. But wants to be ok and prints 'S2::g'
return 0;
}
How can I reach desired behaviour (if it possible)?
A variant of Bryan Chen's answer that looks uglier, but makes it easier to extend to multiple checks, and doesn't require duplicating the code that's shared between D<type-with-f> and D<type-without-f>, is to use an inheritance chain, where each step checks one additional member. The only duplication required is the inheritance of constructors, if appropriate.
struct A {
void f() { }
void g() { }
void i() { }
};
// The generic case. D<T, char[N]> simply provides what D<T, char[N+1]> provides.
template <typename T, typename U = char[1]>
struct D : D<T, char[sizeof(U) + 1]> {
using D<T, char[sizeof(U) + 1]>::D;
};
// The end of the chain. This is where T gets inherited. It declares all of its own
// specialisations as its friends, so that they can access other members of T.
template <typename T>
struct D<T, char[6]> : private T {
template <typename, typename>
friend struct D;
D(int) { }
void fun() { }
};
// Check for T::f.
template <typename T>
struct D<T, char[2 + !sizeof(&T::f)]> : D<T, char[3]> {
using D<T, char[3]>::D;
using T::f;
};
// Check for T::g.
template <typename T>
struct D<T, char[3 + !sizeof(&T::g)]> : D<T, char[4]> {
using D<T, char[4]>::D;
using T::g;
};
// Check for T::h.
template <typename T>
struct D<T, char[4 + !sizeof(&T::h)]> : D<T, char[5]> {
using D<T, char[5]>::D;
using T::h;
};
// Check for T::i.
template <typename T>
struct D<T, char[5 + !sizeof(&T::i)]> : D<T, char[6]> {
using D<T, char[6]>::D;
using T::i;
};
int main() {
D<A> d = 4; // ok: verify that constructors got inherited
// A &a = d; // error: verify that inheritance of A is private
d.f(); // ok: verify that f got inherited
d.g(); // ok: verify that g got inherited
// d.h(); // error: verify that h is not available
d.i(); // ok: verify that i got inherited
d.fun(); // ok: verify that the inheritance chain didn't get broken
}
Note: instead of checking &T::f, you may want to do something with std::declval<T>().f() instead. The former cannot handle overloaded functions.
C++ partial template specialization and use decltype(void(&T::g)) for SFINAE
#include <iostream>
#include <type_traits>
struct S1 {
void f() { std::cout << "S1::f\n"; }
};
struct S2 {
void f() { std::cout << "S2::f\n"; }
void g() { std::cout << "S2::g\n"; }
};
template <class T, class V = void>
struct D : private T {
using T::f;
};
template <class T>
struct D<T, decltype(void(&T::g))> : private T {
using T::f;
using T::g; // need this only if T provides g() function
};
int main() {
D<S1>().f(); // ok. Prints 'S1::f'
D<S2>().f(); // ok. Prints 'S2::f'
D<S2>().g(); // ok. Prints 'S2::g'
return 0;
}
Live Demo
Edit:
This is another approach that is more flexible, but I have no idea how does private virtual inheritance works with real use cases. Please let me know if it may cause any issue (e.g. UB).
#include <iostream>
#include <type_traits>
struct S1 {
void f() { std::cout << "S1::f\n"; }
};
struct S2 {
void f() { std::cout << "S2::f\n"; }
void g() { std::cout << "S2::g\n"; }
};
struct S3 {
void g() { std::cout << "S3::g\n"; }
};
template <class T, class = void>
struct D_f {};
template <class T>
struct D_f<T, decltype(void(&T::f))> : private virtual T {
using T::f;
};
template <class T, class = void>
struct D_g {};
template <class T>
struct D_g<T, decltype(void(&T::g))> : private virtual T {
using T::g;
};
template <class T>
struct D : D_f<T>, D_g<T> {
};
int main() {
D<S1>().f();
D<S2>().f();
D<S2>().g();
D<S3>().g();
return 0;
}
Live Demo
Related
class Base {};
class Derived : public Base {};
class SomeClass
{
template<typename T>
static void SetContent(T* pChild, OVariant content)
{
LOG_ASSERT(0, "All classes must be specialized!. Please provide implementation for this class.");
}
};
template <>
void SomeClass::SetContent(Base* value)
{
LOG_TRACE("Yay!");
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
When I call foo.SetContent(derived), I get the Assert. Is it not possible for the derived class to use the specialization for it's base class?
You can convert a Derived* to a Base*, but I think you rather want to specialize for all T that have Base as base
#include <type_traits>
#include <iostream>
class Base {};
class Derived : public Base {};
template <typename T,typename = void>
struct impl {
void operator()(T*) {
std::cout <<"All classes must be specialized!. Please provide implementation for this class.\n";
}
};
template <typename T>
struct impl<T,std::enable_if_t<std::is_base_of_v<Base,T>>> {
void operator()(T*) {
std::cout << "Yay\n";
}
};
class SomeClass
{
public:
template<typename T>
static void SetContent(T* pChild)
{
impl<T>{}(pChild);
}
};
struct bar{};
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);
bar b;
foo.SetContent(&b);
}
Output:
Yay
All classes must be specialized!. Please provide implementation for this class.
//want it to call SomeClass::SetContent(Base* value)
Note that if the template argument is deduced, it will be deduced as Derived not as Base and the argument is Derived*. SomeClass::SetContent<Base>(&derived); would already work as expected with your code (because Derived* can be converted to Base*).
A workaround would be to have all SetContent's explicit specializations to form an overload set. You will have to do it yourself:
#include <iostream>
#include <utility>
#include <functional>
class Base {};
class Derived : public Base {};
template <class... T>
struct Overloads : T... {
Overloads(const T &... t) : T(t)... {}
using T::operator()...;
};
template <class R, class... Args>
struct FunctionP {
using F = R(Args...);
FunctionP(F *t) : t_(t) {}
R operator()(Args... args) const {
return std::invoke(t_, std::forward<Args>(args)...);
}
F *t_;
};
struct SomeClass {
template<typename T>
static void SetContent(T *x) {
Overloads o(FunctionP(&SetContentImpl<Base>)); // enumerates all the specializations here
if constexpr (std::is_invocable_v<decltype(o), T *>) {
o(x);
} else {
SetContentImpl(x);
}
}
template<typename T>
static void SetContentImpl(T *) {
std::cout << "1";
}
};
template <>
void SomeClass::SetContentImpl(Base *) {
std::cout << "2";
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
godbolt
I have a template class and a member function print() to print the data.
template<typename T>
class A
{
public:
T data;
void print(void)
{
std::cout << data << std::endl;
}
// other functions ...
};
Then, I want to either print scalar data or vector data, so I give a specialized definition and get a compiler error.
template<typename T>
void A<std::vector<T>>::print(void) // template argument list error
{
for (const auto& d : data)
{
std::cout << d << std::endl;
}
}
Question: Why does this member function specialization get an error? What is the correct way to define a print function for a vector?
Solution 1: I have tested the following definition.
template<typename T>
class A<std::vector<T>>
{
public:
std::vector<T> data;
void print(void) { // OK
// ...
}
}
This one worked, but I have to copy the other member functions into this specialized class.
EDIT:
Solution 2: To prevent copy all the other member functions, I define a base class containing the common member functions and inherit from the base class:
template<typename T>
class Base
{
public:
T data;
// other functions ...
};
template<typename T>
class A : public Base<T>
{
public:
void print(void)
{
std::cout << this->data << std::endl;
}
};
template<typename T>
class A<std::vector<T>> : public Base<std::vector<T>>
{
public:
void print(void)
{
for (const auto& d : this->data)
{
std::cout << d << std::endl;
}
}
};
This solution works well. Are there some better or more conventional solutions?
Why does this member function specialization get error?
When you instantiate the template class A for example A<std::vector<int>>, the template parameter T is equal to std::vector<int>, not std::vector<T>, and this a specialization case of the function. Unfortunately this can not be done with member functions as mentioned in the comments.
Are there some better solutions?
Yes; In c++17 you could use if constexpr with a trait to check the std::vector, like this.
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
void print() const /* noexcept */
{
if constexpr (is_std_vector<T>::value) // when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else // for types other than `std::vector<>`
{
std::cout << mData << std::endl;
}
}
};
(See Live Online)
This way you keep only one template class and the print() will instantiate the appropriate part according to the template type T at compile time.
If you don not have access to C++17, other option is to SFINAE the members(Since c++11).
#include <type_traits> // std::false_type, std::true_type, std::enbale_if
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
template<typename Type = T> // when T == `std::vector<>`
auto print() const -> typename std::enable_if<is_std_vector<Type>::value>::type
{
for (const auto element : mData)
std::cout << element << "\n";
}
template<typename Type = T> // for types other than `std::vector<>`
auto print() const -> typename std::enable_if<!is_std_vector<Type>::value>::type
{
std::cout << mData << std::endl;
}
};
(See Live Online)
What if I have more other data types like self-define vector classes
or matrices? Do I have to define many is_xx_vector?
You can check the type is a specialization of the provided one like as follows. This way you can avoid providing many traits for each type. The is_specialization is basically inspired from this post
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// custom MyVector (An example)
template<typename T> struct MyVector {};
template<typename Test, template<typename...> class ClassType>
struct is_specialization final : std::false_type {};
template<template<typename...> class ClassType, typename... Args>
struct is_specialization<ClassType<Args...>, ClassType> final : std::true_type {};
And the print function could be in c++17:
void print() const /* noexcept */
{
if constexpr (is_specialization<T, std::vector>::value)// when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else if constexpr (is_specialization<T, ::MyVector>::value) // custom `MyVector`
{
std::cout << "MyVector\n";
}
else // for types other than `std::vector<>` and custom `MyVector`
{
std::cout << mData << std::endl;
}
}
(See Live Online)
You need to implement a template class that uses a vector as template parameter. This worked for me.
template<typename T>
class A
{
public:
T data;
void print(void) {
std::cout << "Data output" << std::endl;
}
// other functions ...
};
template <typename T>
class A<std::vector<T>>
{
public:
std::vector<T> data;
void print() {
for (auto i : data) {
std::cout << "Vector output" << std::endl;
}
}
};
You could always use named tag dispatching to check if type provided by template user is vector.
A<std::vector<T>> notation won't work as you both try to take into account that T is type and vector of types which is contradicting with itself.
Below is code I used named tag dispatching as solution to your problem:
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
template<typename T> struct is_vector : public std::false_type {};
template<typename T, typename A>
struct is_vector<std::vector<T, A>> : public std::true_type {};
template<typename T>
class A
{
public:
T data;
void print(std::true_type) {
for (auto& a : data) { std::cout << a << std::endl; }
}
void print(std::false_type) {
std::cout << data << std::endl;
}
void print() {
print(is_vector<T>{});
}
};
int main()
{
A<int> a;
a.data = 1;
a.print();
A<std::vector<int>> b;
b.data = { 1, 2 ,3 ,4 ,5 };
b.print();
return 0;
}
Succesfully compiled with https://www.onlinegdb.com/online_c++_compiler
Based on answer: Check at compile-time is a template type a vector
You can dispatch printing to another member function (static or not). For example:
template<typename T>
class A {
public:
T data;
void print() const {
print_impl(data);
}
private:
template<class S>
static void print_impl(const S& data) {
std::cout << data;
}
template<class S, class A>
static void print_impl(const std::vector<S, A>& data) {
for (const auto& d : data)
std::cout << d;
}
};
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 have a
template <typename T>
class A :
class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>,
anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T> { ... }
Now, in class A's definition, and/or in its methods, I need to refer to the two superclasses (e.g. to access members in the superclass, or types defined in it etc.) However, I want to avoid repeating the superclass names. At the moment, what I'm doing is something like:
template<typename T>
class A :
class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>,
anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T>
{
using parent1 = class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>;
using parent2 = anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T>;
...
}
which works, obviously, and reduces the number of repetitions to 2; but I would rather avoid even this repetition, if possible. Is there a reasonable way to do this?
Notes:
"Reasonable" e.g. no macros except with very very good justification.
Before A, you may do
namespace detail
{
template <typename T>
using parentA1 = class_with_long_name<T,
and_many_other,
template_arguments,
oh_my_thats_long>;
template <typename T>
using parentA2 = anotherclass_with_long_name<and_many_other,
template_arguments_that,
are_also_annoying,
including_also,
T>;
}
And then
template<typename T>
class A : detail::parentA1<T>, detail::parentA2<T>
{
};
If you inherit with the same access specifier for all classes you could use something like this:
template <typename...S>
struct Bases : public S... {
template <size_t I>
using super = typename std::tuple_element<I, std::tuple<S...>>::type;
};
This will give you access to all base classes in the order you inherit from them via super<index>.
Short example:
#include <iostream>
#include <tuple>
template <typename...S>
struct Bases : public S... {
template <size_t I>
using super = typename std::tuple_element<I, std::tuple<S...>>::type;
};
class Foo
{
public:
virtual void f()
{
std::cout << "Foo";
}
};
class Fii
{
public:
virtual void f()
{
std::cout << "Fii";
}
};
class Faa : private Bases<Foo, Fii>
{
public:
virtual void f()
{
std::cout << "Faa";
super<0>::f(); //Calls Foo::f()
super<1>::f(); //Calls Fii::f()
std::cout << std::endl;
}
};
int main()
{
Faa faa;
faa.f(); //Print "FaaFooFii"
return 0;
}
I think, the best option is what you are already doing. However, if you feel like you absoluletely can not tolerate this, here some funny code (if I would ever see anything like this during code review in production, I'd fight tooth and nail to get rid of it).
template<class... INHERIT_FROM>
struct inherit_publicly : public INHERIT_FROM... {
struct parent_types {
template <int N, class ARG, class... ARGS> struct get {
using type = typename get<N-1, ARGS...>::type;
};
template <class ARG, class... ARGS> struct get<0, ARG, ARGS...> {
using type = ARG;
};
};
template <int N> using parent = typename parent_types::template get<N, INHERIT_FROM...>::type;
};
// **example usage**
struct X { static constexpr const char* const name = "X"; };
struct Y { static constexpr const char* const name = "Y"; };
struct Z { static constexpr const char* const name = "Z"; };
#include <iostream>
struct A : inherit_publicly<X, Y, Z> {
void print_parents() {
std::cout << "First parent type: " << parent<0>::name << "; second: " << parent<1>::name << "; third: " <<parent<2>::name<< "\n";
}
};
int main() {
A a;
a.print_parents();
}
Live demo: http://coliru.stacked-crooked.com/a/37cacf70bed41463
You can just use A::class_with_long_name or A::anotherclass_with_long_name.
template<typename T>
class A
: class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>
, anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T>
{
// If you still want the typedefs.
using parent1 = typename A::class_with_long_name;
using parent2 = typename A::anotherclass_with_long_name;
// If you don't.
void foo() { A::class_with_long_name::bar(); }
};
Based on #Jarod's solution: How about an inside-the-detail subnamespace?
namespace detail { namespace A {
template <typename T>
using parent1 = class_with_long_name<T,
and_many_other,
template_arguments,
oh_my_thats_long>;
template <typename T>
using parent2 = anotherclass_with_long_name<and_many_other,
template_arguments_that,
are_also_annoying,
including_also,
T>;
} // namespace A
} // namespace detail
And then
template<typename T>
class A : detail::A::parent1<T>, detail::A::parent2<T>
{
};
Why won't the compiler select the Interface template when running the following code? Are additional declarations / hints needed or won't this work in general?
I'm just curious if this is actually possible.
class Interface {
public :
virtual void Method() = 0;
virtual ~Interface() { }
};
class Derived : Interface {
public :
void Method() {
cout<<"Interface method"<<endl;
}
};
template<typename T>
struct Selector {
static void Select(T& o) {
cout<<"Generic method"<<endl;
}
};
template<>
struct Selector<Interface> {
static void Select(Interface& o) {
o.Method();
}
};
int i;
Selector<int>::Select(i) // prints out "Generic method" -> ok
Derived d;
Selector<Derived>::Select(d); // prints out "Generic method" -> wrong
// should be "Interface method"
Try this (and #include <type_traits>):
template <typename T, typename = void>
struct Selector
{
static void Select(T & o)
{
std::cout << "Generic method" << std::endl;
}
};
template <typename T>
struct Selector<T,
typename std::enable_if<std::is_base_of<Interface, T>::value>::type>
{
static void Select(Interface & o)
{
o.Method();
}
};
It turns out that enable_if combined with defaulted template arguments can be used to guide partial specialisations.
The compiler will select the version of a function that is the closest match. A function that takes the exact type for a parameter always wins over one that requires a conversion. In this case the template function is an exact match, since it matches anything; the Interface specialization would require the conversion of the parameter from a Derived to an Interface.
This will allow you to achieve the desired result:
#include <iostream>
#include <type_traits>
using namespace std;
class Interface {
public :
virtual void Method() = 0;
virtual ~Interface() { }
};
class Derived : public Interface {
public :
void Method() {
cout<<"Interface method"<<endl;
}
};
template<typename T, typename S = void>
struct Selector {
static void Select(T& o) {
cout<<"Generic method"<<endl;
}
};
template<typename T>
struct Selector<T, typename enable_if< is_base_of<Interface, T>::value >::type> {
static void Select(Interface& o) {
o.Method();
}
};
int main()
{
int i;
Selector<int>::Select(i); // prints out "Generic method" -> ok
Derived d;
Selector<Derived>::Select(d); // prints out "Generic method" -> wrong
// should be "Interface method"
}