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.
Related
This question already has an answer here:
Why can I call base template class method from derived class
(1 answer)
Closed 2 years ago.
I have a template struct which inherits another template struct. It fails compilation in different compilers (in VS2017 and clang on linux). A simple change in the code fixes it.
The code is:
template<typename T>
struct base {
int GetValue2() { return 0; }
};
template<typename T>
struct derived : public base<T>
{
int GetValue() { return GetValue2(); }
};
int main() {
derived<int> a;
return 1;
}
If I change the line
int GetValue() { return GetValue2(); }
to:
int GetValue() { return this->GetValue2(); }
everything compiles just fine.
Does anyone have an idea what's going on?
There is a two-stage name lookup here.
In GetValue(), GetValue2 is not used in a dependent context, so the compiler will look for a name declared at the enclosing namespace scope (which is the global scope here).
It will not look into the base class, since that is dependent and you may declare specializations of Base even after declaring Derived, so the compiler can't really know what i would refer to. If there is no global variable i, then you will get an error message.
In order to make it clear that you want the member of the base class, you need to defer lookup until instantiation time, at which the base class is known. For this, you need to access i in a dependent context, by either using this->i (remember that this is of type Derived*, so is obviously dependent), or using Base::i. Alternatively, Base::i might be brought into scope by a using-declaration.
template<typename T>
struct base {
int GetValue2() { return 0; }
};
template<typename T>
struct derived : public base<T>
{
int GetValue_using() {
using base<T>::GetValue2; // won't compile with gcc, place it outside the function (ok with clang and msvc)
return GetValue2();
}
int GetValue_this() { return this->GetValue2(); }
int GetValue_base() { return base<T>::GetValue2(); }
};
int main() {
derived<int> a;
return 1;
}
I’m trying to puzzle out how clang determines what C++ template static member variables require instantiation, and I’m seeing some behavior that has me confused.
Given the following code:
#include <stdio.h>
#include <typeinfo>
int report(const char *name)
{
printf("Reporting class: %s\n", name);
return 0;
}
template<typename ReportedClass>
class reported_class
{
public:
reported_class()
{
_reported_instances++;
}
private:
static int _reported_instances;
};
template<typename ReportedClass>
int reported_class<ReportedClass>::_reported_instances = report(typeid(ReportedClass).name());
class foo : reported_class<foo>
{
public:
int baz() { return 0; }
};
class bar : reported_class<bar>
{
public:
bar() { }
int baz() { return 0; }
};
int main(int argc, char **argv)
{
return 0;
}
When I run it, I see the following:
$ c++ -v
Apple LLVM version 5.0 (clang-500.0.68) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix
$ c++ test.cpp
$ ./a.out
Reporting class: 3bar
$
Why is the static for reported_class being instantiated, but not the one for foo? The only difference appears to be the presence of a constructor, but I’d expect the reported_class constructor to be called in either case (therefore forcing static instantiation due to use in the constructor). Is there a reason for this in the standard that I’m not aware of, and is this something that can be relied upon?
gcc-4.7.3 displays the same behavior, so I assume that this is something that I"m misunderstanding.
Apparently in the not shown main function you're not instantiating either class.
Then there's no reason for the compiler to generate a default constructor for class foo.
And without that, there's no code that instantiates reported_class<foo>.
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...
Follow-up question to [Does casting to a pointer to a template instantiate that template?].
The question is just as the title says, with the rest of the question being constraints and usage examples of the class template, aswell as my tries to achieve the goal.
An important constraint: The user instantiates the template by subclassing my class template (and not through explicitly instantiating it like in my tries below). As such, it is important to me that, if possible, the user doesn't need to do any extra work. Just subclassing and it should work (the subclass actually registers itself in a dictionary already without the user doing anything other than subclassing an additional class template with CRTP and the subclass is never directly used by the user who created it). I am willing to accept answers where the user needs to do extra work however (like deriving from an additional base), if there really is no other way.
A code snippet to explain how the class template is going to be used:
// the class template in question
template<class Resource>
struct loader
{
typedef Resource res_type;
virtual res_type load(std::string const& path) const = 0;
virtual void unload(res_type const& res) const = 0;
};
template<class Resource, class Derived>
struct implement_loader
: loader<Resource>
, auto_register_in_dict<Derived>
{
};
template<class Resource>
Resource load(std::string const& path){
// error should be triggered here
check_loader_instantiated_with<Resource>();
// search through resource cache
// ...
// if not yet loaded, load from disk
// loader_dict is a mapping from strings (the file extension) to loader pointers
auto loader_dict = get_all_loaders_for<Resource>();
auto loader_it = loader_dict.find(get_extension(path))
if(loader_it != loader_dict.end())
return (*loader_it)->load(path);
// if not found, throw some exception saying that
// no loader for that specific file extension was found
}
// the above code comes from my library, the code below is from the user
struct some_loader
: the_lib::implement_loader<my_fancy_struct, some_loader>
{
// to be called during registration of the loader
static std::string extension(){ return "mfs"; }
// override the functions and load the resource
};
And now in tabular form:
User calls the_lib::load<my_fancy_struct> with a resource path
Inside the_lib::load<my_fancy_struct>, if the resource identified by the path isn't cached already, I load it from disk
The specific loader to be used in this case is created at startup time and saved in a dictionary
There is a dictionary for every resource type, and they map [file extension -> loader pointer]
If the dictionary is empty, the user either
didn't create a loader for that specific extension or
didn't create a loader for that specific resource
I only want the first case to have me throw a runtime exception
The second case should be detected at compile / link time, since it involves templates
Rationale: I'm heavily in favor of early errors and if possible I want to detect as many errors as possible before runtime, i.e. at compile and link time. Since checking if a loader for that resource exists would only involve templates, I hope it's possible to do this.
The goal in my tries: Trigger a linker error on the call to check_error<char>.
// invoke with -std=c++0x on Clang and GCC, MSVC10+ already does this implicitly
#include <type_traits>
// the second parameter is for overload resolution in the first test
// literal '0' converts to as well to 'void*' as to 'foo<T>*'
// but it converts better to 'int' than to 'long'
template<class T>
void check_error(void*, long = 0);
template<class T>
struct foo{
template<class U>
friend typename std::enable_if<
std::is_same<T,U>::value
>::type check_error(foo<T>*, int = 0){}
};
template struct foo<int>;
void test();
int main(){ test(); }
Given the above code, the following test definition does achieve the goal for MSVC, GCC 4.4.5 and GCC 4.5.1:
void test(){
check_error<int>(0, 0); // no linker error
check_error<char>(0, 0); // linker error for this call
}
However, it should not do that, as passing a null pointer does not trigger ADL. Why is ADL needed? Because the standard says so:
§7.3.1.2 [namespace.memdef] p3
[...] If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup or by qualified lookup until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). [...]
Triggering ADL through a cast, as in the following definition of test, achieves the goal on Clang 3.1 and GCC 4.4.5, but GCC 4.5.1 already links fine, as does MSVC10:
void test(){
check_error<int>((foo<int>*)0);
check_error<char>((foo<char>*)0);
}
Sadly, GCC 4.5.1 and MSVC10 have the correct behaviour here, as discussed in the linked question and specifically this answer.
The compiler instatiates a template function whenever it is referenced and a full specification of the template is available. If none is available, the compiler doesn't and hopes that some other translation unit will instantiate it. The same is true for, say, the default constructor of your base class.
File header.h:
template<class T>
class Base
{
public:
Base();
};
#ifndef OMIT_CONSTR
template<class T>
Base<T>::Base() { }
#endif
File client.cc:
#include "header.h"
class MyClass : public Base<int>
{
};
int main()
{
MyClass a;
Base<double> b;
}
File check.cc:
#define OMIT_CONSTR
#include "header.h"
void checks()
{
Base<int> a;
Base<float> b;
}
Then:
$ g++ client.cc check.cc
/tmp/cc4X95rY.o: In function `checks()':
check.cc:(.text+0x1c): undefined reference to `Base<float>::Base()'
collect2: ld returned 1 exit status
EDIT:
(trying to apply this to the concrete example)
I'll call this file "loader.h":
template<class Resource>
struct loader{
typedef Resource res_type;
virtual res_type load(std::string const& path) const = 0;
virtual void unload(res_type const& res) const = 0;
loader();
};
template<class Resource>
class check_loader_instantiated_with : public loader<Resource> {
virtual Resource load(std::string const& path) const { throw 42; }
virtual void unload(Resource const& res) const { }
};
template<class Resource>
Resource load(std::string const& path){
// error should be triggered here
check_loader_instantiated_with<Resource> checker;
// ...
}
And another file, "loader_impl.h":
#include "loader.h"
template<class Resource>
loader<Resource>::loader() { }
This solution has one weak point that I know of. Each compilation unit has a choice of including either only loader.h or loader_impl.h. You can only define loaders in compilation units that include loader_impl, and in those compilation units, the error checking is disabled for all loaders.
After thinking a bit about your problem, I don't see any way to achieve this. You need a way to make the instantiation "export" something outside the template so that it can be accessed without referencing the instantiation. A friend function with ADL was a good idea, but unfortunately it was shown that for ADL to work, the template had to be instantiated. I tried to find another way to "export" something from the template, but failed to find one.
The usual solution to your problem is to have the user specializes a trait class:
template < typename Resource >
struct has_loader : boost::mpl::false_ {};
template <>
struct has_loader< my_fancy_struct > : boost::mpl::true_ {};
To hide this from the user, you could provide a macro:
#define LOADER( loaderName, resource ) \
template <> struct has_loader< resource > : boost::mpl::true_ {}; \
class loaderName \
: the_lib::loader< resource > \
, the_lib::auto_register_in_dict< loaderName >
LOADER( some_loader, my_fancy_struct )
{
public:
my_fancy_struct load( std::string const & path );
};
It is up to you to determine whether having this macro is acceptable or not.
template <class T>
class Wrapper {};
void CheckError(Wrapper<int> w);
template <class T>
class GenericCheckError
{
public:
GenericCheckError()
{
Wrapper<T> w;
CheckError(w);
}
};
int main()
{
GenericCheckError<int> g1; // this compiles fine
GenericCheckError<char> g2; // this causes a compiler error because Wrapper<char> != Wrapper<int>
return 0;
}
Edit:
Alright this is as close as I can get. If they subclass and either instantiate OR define a constructor that calls the parent's constructor, they will get a compiler error with the wrong type. Or if the child class is templatized and they subclass and instantiate with the wrong type, they will get a compiler error.
template <class T> class Wrapper {};
void CheckError(Wrapper<int> w) {}
template <class T>
class LimitedTemplateClass
{
public:
LimitedTemplateClass()
{
Wrapper<T> w;
CheckError(w);
}
};
// this causes no compiler error
class UserClass : LimitedTemplateClass<int>
{
UserClass() : LimitedTemplateClass<int>() {}
};
// this alone (no instantiation) causes a compiler error
class UserClass2 : LimitedTemplateClass<char>
{
UserClass2() : LimitedTemplateClass<char>() {}
};
// this causes no compiler error (until instantiation with wrong type)
template <class T>
class UserClass3 : LimitedTemplateClass<T>
{
};
int main()
{
UserClass u1; // this is fine
UserClass2 u2; // this obviously won't work because this one errors after subclass declaration
UserClass3<int> u3; // this is fine as it has the right type
UserClass3<char> u4; // this one throws a compiler error
return 0;
}
Obviously you can add other accepted types by defining additional CheckError functions with those types.
template<typename T> struct A {
auto func() -> decltype(T::func()) {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
Seems pretty simple to me. But MSVC fails to compile.
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'func' : is not a member of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see declaration of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see reference to class template instantiation 'A<T>' being compiled
with
[
T=B
]
visual studio 2010\projects\temp\temp\main.cpp(4): error C3861: 'func': identifier not found
Even though the compiler will happily accept calling the function. The below sample compiles fine.
template<typename T> struct A {
void func() {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
I've got the same issue trying to use any types from the template argument.
template<typename T> struct A {
typedef typename T::something something;
};
class B : public A<B> {
typedef char something;
};
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'something' : is not a member of 'B'
Whereas class B clearly defines a type called "something". The compiler is perfectly happy to call functions on an object of type T, T& or T*, but I can't seem to access any types from T.
You are trying to use T::func before it was declared. That's why the compiler shouts at you. Notice that when you derive from a class, the class is generated if it comes from a class template. And the implicit generation of the class (which is called implicit instantiation) necessiates the generation of declarations for all its members (so the compiler knows the sizeof value of the class, and can perform lookup into it).
So it also instantiates the declaration auto func() -> decltype(T::func()) and surely fails here.
There seem to be several issues with your code, one of which looks like a VS10 bug.
You're calling T::func() from A without casting A to T, this is needed as part of CRTP since A doesn't derive from T. -- FixL return static_cast<T*>(this)->func();
What you're passing to decltype looks like a static function invocation while func is in fact an instance function. Since decltype doesn't actually run the function you should do something like this decltype(static_cast<T*>(nullptr)->func())
func is private in B and can't be called from A -- Fix: change A to be a struct
This looks like a bug in VS10, even after all these fixes I get an error that you're trying to use an undefined class B in the decltype.
As a workaround can you refactor func out into a base class? (now we need two template parameters, one for casting to and one for decltype thus creating a new idiom CRTPEX)
struct Base {
void func() { }
};
template<typename T, typename U> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<U*>(this)->func();
}
};
struct B : public A<Base, B>, public Base {
};
I see that g++ also chokes on this decltype can anyone confirm that this is a defect? If so I will open a bug for Microsoft. It is my understanding that the following code is valid but neither g++ nor VC10 compile it.
template<typename T> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<T*>(this)->func();
}
};
struct B : public A<B> {
void func() {}
};
First, I think that the close-to-proper code is:
template<typename T> struct A {
auto func()
-> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
As Motti pointed out. However that still fails, and I think for the reason that the return type of the base has to be known when B is declated to inherit from A<B>, but since B is not defined yet, it becomes a chicken and egg problem.
However, it may be finally be possible in C++1y by using simply auto (without decltype), I tried with gcc-4.8.2
template<typename T> struct A {
auto func()
//c++1y// -> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
This compiles (c++ -std=c++1y) and runs:
int main(){
B b; b.func();
}
Two disclaimers: I don't know why this works. I don't know how standard it is.