The following code compiles using GCC 4.4.6 and Comeau 4.3.10.
#include <iostream>
struct A { int name; };
template<typename T> struct C : T { using T::name; };
struct B : private A { friend struct C<B>; };
int main()
{
C<B> o;
o.name = 0;
}
It gives the following error in VC++10:
main.cpp(4): error C2877: 'A::name' is not accessible from 'A'
main.cpp(10): error C2247: 'A::name' not accessible because 'B' uses 'private' to inherit from 'A'
What's a good cross-compiler workaround that allows o.name = 0;?
Note: Adding using A::name to B takes care of the problem, but publishes the A::name member to everyone, whereas it should only be visible to a particular template instantiation, namely C<B>.
Work around is what #kerrekSB suggested, add using A::name; in class B:
struct A { int name; };
template<typename T> struct C : T { using T::name; };
struct B : private A {
using A::name;
friend struct C<B>;
};
your initial example didn't work cause class A is private to B and class C<B> is friend of B but when you access member name from object of C<B> , line using T::name; creates problem since the class B doesn't has any member name in it. it's scope search which find the member name when you try to access it via object of class B
Edit :
Adding using A::name to B takes care of the problem, but publishes the
A::name member to everyone, whereas it should only be visible to a
particular template instantiation, namely C
if that's the case , then simply declare statement using A::name; in private section in class B i.e
struct B : private A {
protected: using A::name;
public:
friend struct C<B>;
};
There seems to be a fundamental difference in visibility considerations between gcc and VC++ when using member using-declarations; check this simplified example without templates:
struct A { int name; };
struct B: private A { friend struct C; };
struct C: B {using B::name; };
int main()
{
C o;
o.name = 0;
}
It will compile on gcc but not on VC++ (with basically the same error as in the question). Will have to consult the standard on who is doing it right...
Related
I have stumbled upon something that I don't quite understand. I have a class hierarchy that uses private inheritance where each of the structs defines a different function call operator. Oddly enough, the function call operator from the topmost struct is available in the most derived struct, despite the fact that a using directive is only used in the first derived struct. A regular function foo, though, is not accessible there, as expected. Example:
#include <string>
#include <vector>
#include <iostream>
struct A {
void foo() {}
void operator()(bool) {
std::cout << "bool\n";
}
};
struct B : private A {
using A::foo;
using A::operator();
void operator()(std::string) {}
};
struct C : private B {
using B::operator();
void operator()(std::vector<int>) {}
};
struct D : private C {
using C::operator();
void operator()(std::vector<double>) {}
};
int main() {
D d{};
d(false); // <-- works!
//d.foo(); // <-- error: ‘void A::foo()’ is private within this context
return 0;
}
I happened upon this while trying to implement the C++17 overload object for use with boost::apply_visitor using pre-C++17 code. I solved it using recursive inheritance, where each object pulls in the function call operator of its direct base class like so:
template<typename T, typename... Ts>
struct visitor : private T, private visitor<Ts...> {
using T::operator();
using visitor<Ts...>::operator();
visitor(T func, Ts... tail) : T{ std::move(func) }, visitor<Ts...>{ std::move(tail)... } {}
};
template<typename T>
struct visitor<T> : private T {
using T::operator();
visitor(T func) : T{ std::move(func) } {}
};
template<typename... Ts>
visitor<Ts...> make_visitor(Ts&&... funcs) {
return visitor<Ts...>{ std::forward<Ts>(funcs)... };
}
I wanted to understand why all of the operators are available in the most derived object. That's how I came up with the above example. Compiler is g++ 11.1.0.
Can anyone enlighten me as to what's going on here?
As pointed out by others in comments, it turns out I just had an error in my thinking. The using pulls in all the operators available in the respective base class, including the ones that were imported by the base class itself, and therefore all the operators will be available in the bottommost object. foo, on the other hand, is just handed down to B.
I have some template class that has two private static members.
Users define a traits struct and provide it to the template class, which then derives from it.
Then in a c++ file the user define the static members, with one member initialized from the other.
For some reason I get a "class has not been declared" error if I dont fully specify the namespace for the arg. This is only an issue when I'm in a nested namespace, there is no issue if you define the type in a single top level namespace, which makes me think this is a compiler bug.
Trimmed down example below, compiling with gcc 7.2
template<typename Traits>
struct Base
{
static int x;
static int y;
};
namespace foo::bar
{
struct BarTraits
{
};
using Bar = Base<BarTraits>;
template<> int Bar::x = 0;
template<> int Bar::y( Bar::x ); //error
//template<> int Bar::y( foo::bar::Bar::x ); //no error
}
According to C++ standard temp.expl.spec#3
An explicit specialization may be declared in any scope in which the corresponding primary template may be defined.
Your code violates this statement, because Bar::x and Bar::y are specialized in namespace foo::bar.
GCC incorrectly accepts first two specializations because of known defect https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56119
The following fixed code
template<typename Traits>
struct Base {
static int x;
static int y;
};
struct BarTraits {};
using Bar = Base<BarTraits>;
template<> int Bar::x = 0;
template<> int Bar::y( Bar::x );
is accepted by GCC, Clang, MSVC: https://gcc.godbolt.org/z/MPxjTzbah
I am not able isolate this error in a small sample to demonstrate here, but the even the error message is so self-contradicting that maybe one can have an idea if this is a bug or not, without testing.
I have a struct that is (presumably, publicly) deriving another one, yet clang insists this is implicitly private inheritance:
error: 'next' is a private member of 'base'
note: constrained by implicitly private inheritance here
struct derived_temp <key> : base <derived>
while g++ compiles fine. I have only changed the actual names of the classes to make messages more readable. The code looks like this:
template </*...*/>
struct base : //...
{
private:
//...
public:
template <typename I> I next(I i) const { return /*...*/; }
//...
};
template <typename /*...*/>
struct derived_temp;
struct key { /*...*/ };
using derived = derived_temp <key>;
template <>
struct derived_temp <key> : base <derived>
{
//...
};
I have tried to keep the form of the code exactly the same as in my project, only changing names and commenting out parts of it.
The error is caused by attempting to call function next() on a temporary object of type derived.
My only explanation is that this may be a bug of clang (yet, I cannot reproduce it in a small sample) that forces me to change
struct derived_temp <key> : base <derived>
to the more explicit
struct derived_temp <key> : public base <derived>
Any idea?
Code:
struct T1 {
int x;
};
struct T2 : T1 {
int y;
};
int main( int argc, char * argv[] ) {
T2 t2;
t2.x = 3;
return t2.x;
}
Building/running:
~ clang blah.cc -o blah; ./blah; echo $?
3
~ clang blah.cc -std=c++11 -o blah; ./blah; echo $?
3
In short: defaults to public inheritance.
I spent a little more time on this to get it closer to the OPs code; this is what I put together (please forgive the typos; I'm using an airgapped machine to test this out):
template <class T>
struct base {
T x;
template <typename I> I blah( I i ) const { return i + x.k.y; }
}
template <class T>
struct derived_temp;
struct key { int y; };
using derived = derived_temp<key>;
template <>
struct derived_temp<key> : base <derived> {
int z;
key k;
};
int main( int argc, char * argv[] ) {
derived d;
d.x = 1;
d.k.y = 2;
d.z = 3;
return 0;
}
Built with:
~ clang --version
clang version 3.4 (tags/RELEASE_34/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
~ clang++ test.cc -o test -std=c++11
I get two basic errors (I'm not quoting the full thing since I'd have to manually type it all):
test.cc:3:5: error: field has incomplete type 'derived_temp<key>'
test.cc:21:5: error: no member named 'x' in 'derived_temp<key>'
As I stared at this, trying to understand both your motivation/intent as well as what the errors said, it occurs to me you're attempting to do circular inheritance to define things in a circular fashion that may not even be possible.
Something is a little off there. Structs should use public inheritance by default. Forget the templates for a moment and the using directive.
Test with the simplest code which sets up your suspected fail case:
struct Base
{
int i;
};
struct Derived : Base
{
};
Now try access i from an instance of Derived. If that works, and it should, start to add features until it has all the same kinds of components as your original code.
Right now I don't have clang to test it myself. So I'm just suggesting a way forward.
Two-phase lookup question:
Is there a more synthetic way to write this code, i.e. avoiding all those using directives?
Something like using CBase<T>; is what I would like, but it is not accepted.
#include <iostream>
template <typename T>
class CBase
{
protected:
int a, b, c, d; // many more...
public:
CBase() {
a = 123; c = 0;
}
};
template <typename T>
class CDer : public CBase<T>
{
// using CBase<T>; // error, but this is what I would like
using CBase<T>::a;
using CBase<T>::b;
//...
public:
CDer() {
std::cout << a << this->c;
}
};
int main()
{
CDer<int> cd;
}
In my real code there are many more member variables/functions, and I was wondering if it is possible to write shorter code in some way.
Of course, using the this->c syntax does not solve the problem...
Thank's!
gcc 4.1
MacOS X 10.6
I reduced the testcase and then consider three options
template<typename T> struct Base { int a; };
Option 1
template<typename T> struct Der : Base<T> {
void f() {
int &ra = Der::a;
// now use ra
}
}
Option 2
template<typename T> struct Der : Base<T> {
void f() {
// use this->a instead
// or Der::a
}
}
Option 3
// use your using declarations
It doesn't look like most of those variables are parameterized. Does CBase use them all, or just a? If not, move them into a new non-template base of CDer.
Or, pack them all into a POD struct and then using CBase<T>::m_ints;.
High overhead solution: non-templated virtual base.
Not sure but worth a try: nest the definition of CDer inside CBase and then typedef it into namespace scope.
i got a compile error which i do not understand.
i have a h/cpp file combination that does not contain a class but just defines some utility functions. when i try to use a struct that is defined in another class i get the error:
error C2027: use of undefined type 'B::C'
so, stripped down to the problem, the h-file looks like this
namespace A {
void foo(B::C::SStruct const & Var);
}
the definition of SStruct is in a class which is in another h-file, that is of course included.
namespace B {
class C {
public:
struct SStruct { };
};
}
the strange thing is, i can use this struct in other classes fine, it just seems to be related to this one h-file which contains just utility functions.
what am i missing here?
thanks!
After correcting missing semicolons etc. this compiles:
namespace B {
class C {
public:
struct SStruct { };
};
}
namespace A {
void foo(B::C::SStruct const & Var);
}
Obviously, if the order of the two namespaces were switched, this would not work. Possibly you are #including your headers in the wrong order. If this is the error, that's bad design - you should not allow header order to matter in your code.
I assume you meant "class C", not "Class C".
struct SStruct is private to class C (private being the default visibility of class members).
As such, it is not visible outside class C and its friends, which does not include A::foo().
Class C {
struct SStruct { };
}
==>
class C {
public:
struct SStruct { };
};
Your class is missing a semicolon after the definition. It should be:
namespace B {
class C {
public:
struct SStruct { };
}; // <=== Here
}