C++ Detect private member of friend class with CRTP - c++

I have a CRTP Base class (Bar) which is inherited by a unspecified class. This Derived class may or may not have specific member (internal_foo), and this specific member my or may not have another member (test()).
In this scenario internal_foo will always be public, however test() is private, but declaring Bar as a friend.
I can detect internal_foo using traits fine, because it is public. But I cannot detect test() due to it being private, even though Bar is a friend.
The below example works due to test() being public:
template<class, class = void >
struct has_internal_foo : std::false_type {};
template<class T>
struct has_internal_foo<T,
void_t<
decltype(std::declval<T>().internal_foo)
>> : std::true_type {};
template<class, class = void>
struct internal_foo_has_test : std::false_type {};
template<class T>
struct internal_foo_has_test<T,
void_t<decltype(std::declval<T>().internal_foo.test())
>> : std::true_type {};
class InternalFoo
{
public:
void test()
{
}
};
class BadInternalFoo
{
};
template<class T>
class Bar
{
public:
template<class _T = T>
std::enable_if_t<conjunction<has_internal_foo<_T>, internal_foo_has_test<_T>>::value, void>
action()
{
static_cast<T&>(*this).internal_foo.test();
}
};
class Foo :
public Bar<Foo>
{
public:
InternalFoo internal_foo;
};
class BadFoo :
public Bar<BadFoo>
{
public:
BadInternalFoo internal_foo;
};
void test()
{
Foo foo;
BadFoo bad_foo;
foo.action(); // Compiles. As expected.
bad_foo.action(); // Does not compile. As expected.
}
However this next version does not work, due to test() being private:
template<class, class = void >
struct has_internal_foo : std::false_type {};
template<class T>
struct has_internal_foo<T,
void_t<
decltype(std::declval<T>().internal_foo)
>> : std::true_type {};
template<class, class = void>
struct internal_foo_has_test : std::false_type {};
template<class T>
struct internal_foo_has_test<T,
void_t<decltype(std::declval<T>().internal_foo.test())
>> : std::true_type {};
class InternalFoo
{
public:
template<class T>
friend class Bar;
template<class, class>
friend struct internal_foo_has_test;
private:
void test()
{
}
};
class BadInternalFoo
{
};
template<class T>
class Bar
{
public:
template<class _T = T>
std::enable_if_t<conjunction<has_internal_foo<_T>, internal_foo_has_test<_T>>::value, void>
action()
{
static_cast<T&>(*this).internal_foo.test();
}
};
class Foo :
public Bar<Foo>
{
public:
InternalFoo internal_foo;
};
class BadFoo :
public Bar<BadFoo>
{
public:
BadInternalFoo internal_foo;
};
void test()
{
Foo foo;
BadFoo bad_foo;
foo.action(); // Does not compile
bad_foo.action(); // Does not compile
}
As seen above, I have tried to friend the detection struct too, but that didn't help.
Is there a way to do what I am trying to do?
Ideally I would like this solution to be portable, and not use anything beyond C++11, 14 at the most. (I have implemented void_t & conjunction)
Edit:
The suggested question does not answer this one. That question wants to detect whether a member is public or private, and only access it if it is public, I wish for the detection to return positive on a private member of a friend class.

Summary and the fix
Looks like a GCC 11 bug and your second attempt should in fact work.
However, I recommend rewriting action's definition in either of two ways so you don't even need the member detection idiom:
// Way 1
template<class _T = T>
decltype(std::declval<_T&>().internal_foo.test()) action() {
static_cast<T&>(*this).internal_foo.test();
}
// Way 1, with a different return type via the comma operator
template<class _T = T>
decltype(std::declval<_T&>().internal_foo.test(), std::declval<ReturnType>()) action() {
static_cast<T&>(*this).internal_foo.test();
}
// Way 2
template<class _T = T>
auto action() -> decltype(static_cast<_T&>(*this).internal_foo.test()) {
static_cast<_T&>(*this).internal_foo.test(); // Using _T for consistency
}
Note that I use _T inside the decltype so it's dependent on the template argument and can be SFINAEd. Also note that it's still possible to specify an arbitrary return return type without any enable_ifs.
Details
I took the liberty to prepend #include <type_traits> and using namespace std; to both of your examples and using C++17 so they can be compiled.
Some findings from the comments section:
Your first code (does not) compile(s) as expected with Clang 14, gcc 11 and gcc trunk: https://godbolt.org/z/EbaYvfPE3
Your second code (does not) compile(s) as expected with Clang add gcc trunk, but gcc 11 differs: https://godbolt.org/z/bbKrP8Mb9
There is an easier reproduction example: https://godbolt.org/z/T17dG3Mx1
#include <type_traits>
template<class, class = void>
struct has_test : std::false_type {};
template<class T>
struct has_test<T, std::void_t<decltype(std::declval<T>().test())>> : std::true_type {};
class HasPrivateTest
{
public:
template<class, class>
friend struct has_test;
friend void foo();
private:
void test() {}
};
// Comment the following line to make it compile with GCC 11
static_assert(has_test<HasPrivateTest>::value, "");
void foo() {
static_assert(has_test<HasPrivateTest>::value, "");
}
static_assert(has_test<HasPrivateTest>::value, "");
The code above compiles with Clang 14 and gcc trunk, but is rejected by gcc 11 with three "static assertion failed" messages, one for each assertion. However, commenting out the first static_assert makes all three compilers accept the code.
So it seems like GCC 11 (and earlier) tries to instantiate the template and do access checks depending on the context. Hence, if the first instantiation is outside of a friend, .test() method is not accessible, and the result is kind cached. However, if it's inside the friend void foo(), .test() is accessible and all static_asserts succeed.
#Klaus have pointed out a recent GCC bug whose fix seems relevant: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96204

Related

Is there a work-around for parameter pack expansion in using declarations [duplicate]

The derived class hides the name of an overload set from the base class if the derived class has the same name defined, but we can always introduce that overload set back with using-declaration:
template <class BASE>
class A : public BASE
{
public:
using BASE::some_method;
void some_method();
}
But what if I introduce all overload sets from variadic base classes?
Would I be able to write something like this?
template <class... BASES>
class A : public BASES...
{
public:
using BASES::some_method...;
void some_method();
}
I've considered using a helper class like:
template <class... BASES>
struct helper;
template <>
struct helper<> {};
template <class OnlyBase>
struct helper<OnlyBase> : OnlyBase
{
using OnlyBase::some_method;
};
template <class Base1, class... OtherBases>
struct helper<Base1, OtherBases> : public Base1, public helper<OtherBases...>
{
using Base1::some_method;
using helper<OtherBases...>::some_method;
};
And it does work. But it requires a lot of typing (of course I can use macro but I try to use c++'s compile-time feature whenever possible), and when I want to introduce more methods, i have to change much in that piece of code.
A perfect answer would be a simple syntax, but if there's none, I will go with the helper class.
Here is a trick how to reduce handwriting:
// U<X,Y> is a binary operation on two classes
template<template<class,class>class U, class... Xs> struct foldr;
template<template<class,class>class U, class X> struct foldr<U,X> : X {};
template<template<class,class>class U, class X, class... Xs> struct foldr<U,X,Xs...> : U<X, foldr<U,Xs...>> {};
// our operation inherits from both classes and declares using the member f of them
template<class X, class Y> struct using_f : X,Y { using X::f; using Y::f; };
struct A { void f(int) {} };
struct B { void f(char) {} };
struct C { void f(long) {} };
struct D : foldr<using_f, A, B, C> {};
int main() {
D d;
d.f(1);
d.f('1');
d.f(1L);
return 0;
}
So we should write foldr once, then write simple ad-hoc operations - using_f, using_g, using_f_g
Maybe there is a way to further simplifying. Let me think a bit...

What would a CRTP-based solution to this look like?

I asked the following question in this post (pasted below for convenience). One of the comments suggested that there is a CRTP-based solution to the problem. I am not able to figure out how CRTP is relevant here (well, I never used CRTP before, so I am not used to thinking in these terms). So, how would a CRTP-based solution look like?
Here is the cited question:
Is it possible to write a template function that would possess type information about the base class of the template argument? (assuming that the template argument derives from one class only)
So, I am looking for something like this:
template <class T>
auto f(T t) -> decltype(...) { // ... is some SFINAE magic that
// catches B, the base of T
std::cout << (B)t << std::endl;
}
Some relevant background: I am writing a generic implementation of the A* algorithm. The template argument is a Node structure. So, the user might define:
struct NodeBase {
REFLECTABLE((double)g, (double)f)
// Using the REFLECTABLE macro as described here:
// https://stackoverflow.com/a/11744832/2725810
};
struct NodeData : public NodeBase {
using Base1 = NodeBase;
REFLECTABLE((double)F)
};
I would like to write a function that prints the contents of the node structure. REFLECTABLE does all the hard work of extracting the fields of the struct. However, when the user gives me a NodeData instance, my function needs to print the contents of the NodeBase component as well. I would like to later add overloads of my function for two and three base classes.
to know whether a class derives from a base class we have the std::is_base_of<> template structure, which can be used in conjunction with partial specialisation, or std::enable_if.
Here is a demonstration of using a partially specialised structure to apply a an operation depending on whether it's derived from node_base or not (in this case, it just prints the base object but you could do any other operation)
#include <iostream>
#include <type_traits>
// base class
struct node_base
{
};
std::ostream& operator<<(std::ostream& os, const node_base& nb)
{
os << "node_base_stuff";
return os;
}
// a class derived from node_base
struct node : public node_base
{
};
// a class not derived from node_base
struct not_node
{
};
// apply the general case - do nothing
template<class T, class = void>
struct report_impl
{
static void apply(const T&) {};
};
// apply the case where an object T is derived from node_base
template<class T>
struct report_impl<T, std::enable_if_t< std::is_base_of<node_base, T>::value > >
{
static void apply(const T& t) {
std::cout << static_cast<const node_base&>(t) << std::endl;
};
};
// the general form of the report function defers to the partially
// specialised application class
template<class T>
void report(const T& t)
{
report_impl<T>::apply(t);
}
using namespace std;
// a quick test
auto main() -> int
{
node n;
not_node nn;
report(n);
report(nn);
return 0;
}
expected output:
node_base_stuff
Here is my own first solution. It is not CRTP though and it suffers from a huge drawback as explained at the end of the answer:
template <class Base1_ = void, class Base2_ = void, class Base3_ = void,
class Base4_ = void>
struct ManagedNode;
// For classes that do not derive
template <> struct ManagedNode<void, void, void, void> {
using Base1 = void; using Base2 = void; using Base3 = void;
using Base4 = void;
};
// To avoid inaccessible base
// See http://stackoverflow.com/q/34255802/2725810
struct Inter0: public ManagedNode<>{};
// For classes that derive from a single base class
template <class Base1_>
struct ManagedNode<Base1_, void, void, void> : public Inter0,
public Base1_ {
using Base1 = Base1_;
};
// To avoid inaccessible base
template <class Base1_>
struct Inter1: public ManagedNode<Base1_>{};
// For classes that derive from two base classes
template <class Base1_, class Base2_>
struct ManagedNode<Base1_, Base2_, void, void> : public Inter1<Base1_>,
public Base2_ {
using Base2 = Base2_;
};
// Some user classes for testing the concept
struct A : public ManagedNode<> {
int data1;
};
struct B : public ManagedNode<> {};
struct C : public ManagedNode<A, B> {};
int main() {
C c;
std::cout << sizeof(c) << std::endl;
return 0;
}
This code produces the output of 12, which means that c contains the data1 member three times! For my purposes this drawback over-weighs the benefits of the reflection that this approach provides. So, does anyone have a suggestion for a better approach?

How to use a nested typedef in a template?

I want to derive a type Test from a templated type Base which I specialise on the derived type (i.e. Base<Test>).
Inside the templated type, I want to make use of a typedef defined in the derived type (the template parameter).
However, I get this compile error:
error C2039: 'X' : is not a member of 'Test'
Here is the code snippet:
template <typename T>
class Base
{
protected:
void func(typename T::X x) {}
};
class Test : public Base<Test>
{
public:
typedef int X;
};
Is this doable, and if so, what is the fix I need to make?
(I see a couple of answers for this kind of problem but it looks like my scenario isn't fixed by prefixing typename - is it something to do with deriving from a template specialised with the derived type?)
Alternatively to the typedef, you can also declare the type as second template argument in the base class:
template <typename T, typename X>
class Base
{
protected:
void func(X x) {}
};
class Test : public Base<Test, int>
{
public:
// typedef int X;
};
You have a circularity which cannot be resolved with forward declarations. But this will work, although (I suspect) not quite so strongly defined as you wanted.
template <typename T>
class Base
{
protected:
template<typename Y>
void func(Y x) {}
};
class Test : public Base<Test>
{
public:
typedef int X;
};
If func were public, then you could then write
Test t;
Test::X x;
t.func(x)
which is satisfactory for any use of the Curiously Recurring Template Pattern I think of.
This works for me:
template <typename T> struct Traits;
template <typename Derived>
class Base
{
protected:
void func(typename Traits<Derived>::X x) {}
};
class Test;
template <> struct Traits<Test>
{
typedef int X;
};
class Test : public Base<Test>
{
};
I'm not sure about this behavior, maybe someone can clarify it. But as I understand by the moment you do : public Base<Test> the type name X doesn't exists (since is declared below).
If you create a wrapper class before making the inheritance the type would exists by the moment you do the inheritance and the template instantiation will work.
This compiles with VC++ 2013
template <typename T>
class Base
{
protected:
void func(typename T::X x) {}
};
class TestWrapper
{
public:
typedef int X; //Declared, now it exists for the compiler
};
class Test
:public Base<TestWrapper> //Compiles correctly
{
};

C++ - How to introduce overload set from variadic number of bases.

The derived class hides the name of an overload set from the base class if the derived class has the same name defined, but we can always introduce that overload set back with using-declaration:
template <class BASE>
class A : public BASE
{
public:
using BASE::some_method;
void some_method();
}
But what if I introduce all overload sets from variadic base classes?
Would I be able to write something like this?
template <class... BASES>
class A : public BASES...
{
public:
using BASES::some_method...;
void some_method();
}
I've considered using a helper class like:
template <class... BASES>
struct helper;
template <>
struct helper<> {};
template <class OnlyBase>
struct helper<OnlyBase> : OnlyBase
{
using OnlyBase::some_method;
};
template <class Base1, class... OtherBases>
struct helper<Base1, OtherBases> : public Base1, public helper<OtherBases...>
{
using Base1::some_method;
using helper<OtherBases...>::some_method;
};
And it does work. But it requires a lot of typing (of course I can use macro but I try to use c++'s compile-time feature whenever possible), and when I want to introduce more methods, i have to change much in that piece of code.
A perfect answer would be a simple syntax, but if there's none, I will go with the helper class.
Here is a trick how to reduce handwriting:
// U<X,Y> is a binary operation on two classes
template<template<class,class>class U, class... Xs> struct foldr;
template<template<class,class>class U, class X> struct foldr<U,X> : X {};
template<template<class,class>class U, class X, class... Xs> struct foldr<U,X,Xs...> : U<X, foldr<U,Xs...>> {};
// our operation inherits from both classes and declares using the member f of them
template<class X, class Y> struct using_f : X,Y { using X::f; using Y::f; };
struct A { void f(int) {} };
struct B { void f(char) {} };
struct C { void f(long) {} };
struct D : foldr<using_f, A, B, C> {};
int main() {
D d;
d.f(1);
d.f('1');
d.f(1L);
return 0;
}
So we should write foldr once, then write simple ad-hoc operations - using_f, using_g, using_f_g
Maybe there is a way to further simplifying. Let me think a bit...

Change property access based on template argument

I have a base class that is a template that looks like this:
template <typename T>
class Foo
{
public:
T bar;
};
What I'd like to do is introduce a template argument that can be used to control the access mode of the member bar.
Something like this:
template <typename T,bool publicBar=true>
class Foo
{
public:
// If publicBar is false, insert protected: here
T bar;
};
Is this possible?
Thanks.
Edit:
Many asked so, for those interesting in why I'm doing this, here's my real code!
// Class used for automatic setter/getter generation.
template <typename T,publicSetter=true>
class Property
{
public:
Property(){}
Property(T value):mObject(object){}
T operator()()const
{
return mObject;
}
public: // This is where I want the protected:
virtual void operator()(T newObject)
{
this->mObject = newObject;
}
private:
T mObject;
};
This can be done using partial template specialization:
template <typename T,bool publicBar>
class Foo
{
};
template <typename T>
class Foo<T,true>
{
public:
T bar;
};
template <typename T>
class Foo<T,false>
{
protected:
T bar;
};
The only gotcha here is that you would need to replicate the entire class for each specialization... UNLESS you wanted to make it on top of a base class, e.g.:
template <typename T>
class FooBase
{
//the goods go here
};
template <typename T,bool publicBar>
class Foo : public FooBase<T>
{
};
template <typename T>
class Foo<T,true> : public FooBase<T>
{
public:
T bar;
};
template <typename T>
class Foo<T,false> : public FooBase<T>
{
protected:
T bar;
};
Yes, this is possible using partial specialization. Whether it's advisable is a another question - for a start, this solution doesn't scale as you need 2^n specializations where n is the number of variables you're controlling the access of. And do you really want the interface of your class to change based on the value of a template parameter?
It seems like you're creating something difficult to maintain, difficult to understand and overly clever.
Nevertheless, if you decide this is a good idea, here's how you would do it:
template <typename T, bool publicBar=true>
class Foo
{
public:
T bar;
};
template <typename T>
class Foo<T,false>
{
protected:
T bar;
};
Yes, using explicit class template specialization:
template<bool B> class Foo;
template<> class Foo<true>
{
public:
int n_;
};
template<> class Foo<false>
{
protected:
int n_;
};
int main()
{
Foo<true> fa;
fa.n_;
Foo<false> fb;
fb.n_; // ERROR: protected
}
Seems like a really bad idea, though. Why would you want to?
I think you could do this with a template specialization. Totally untested code.
template <typename T,bool publicBar=true>
class Foo
{
public:
// If publicBar is false, insert protected: here
T bar;
};
template <typename T, false>
class Foo
{
protected:
// If publicBar is false, insert protected: here
T bar;
};
But really consider why you'd want to do this. public data is really dangerous for encapsulation, and protected is nearly so. A solution that's able to utilize a client-API will probably be more maintainable in the long-term.
How about
template<typename T>
struct FooBase {
T bar;
};
template<typename T, bool publicBar>
class Foo : public FooBase<T> {};
template<typename T>
class Foo<T, false> : protected FooBase<T> {};
This way you don't have to define bar a number of times but only once.