MSVC is happy with this code but GCC isn't so keen - c++

This code compiles in MSVC (19.00.23918) but GCC doesn't like it unless I use this-> access to member operator when I call Detach_Internal().
Is GCC catching a potential bug here that MSVC isn't? As a general rule is it a better idea to use this-> at all times when referencing functions in base classes?
Note GCC will compile it with -fpermissive.
#include <memory>
namespace Events
{
template<typename T>
class EventBase
{
protected:
void Detach_Internal(std::weak_ptr<void> const & p)
{
}
};
template<typename T>
class Event : public EventBase<T>
{
public:
void Detach(std::weak_ptr<void> const & p)
{
Detach_Internal(p);
}
};
}
int main(void)
{
auto event = std::make_unique<Events::Event<void()>>();
}
33:30: error: there are no arguments to 'Detach_Internal' that depend on a template parameter, so a declaration of 'Detach_Internal' must be available [-fpermissive]

Is GCC catching a potential bug here that VS isn't? As a general rule is it a better idea to use this-> at all times when referencing functions in base classes?
GCC is correct. You should add this-> when referring names in dependent base class (i.e. EventBase<T>, which depends on template parameter T).
Otherwise as a nondependent name, Detach_Internal won't be looked up in dependent base class EventBase<T>.
To solve the issue you can make the name Detach_Internal dependent, then it will be looked up at the time of instantiation, at that time the exact base class template specialization is fixed. e.g.
this->Detach_Internal(p);
EventBase<T>::Detach_Internal(p);
using EventBase<T>::Detach_Internal;
Detach_Internal(p);

Related

Why class::class::class::staticClassMember() compiles (in C++)?

I must have missed something in C++ specification because I can't explain why the following code compiles successfully:
class MyClass { static void fun(); };
int main() { MyClass::MyClass::MyClass::fun(); }
Could somebody point me to the standard or just explain me the semantics? I would guess that only one MyClass:: is allowed. Two MyClass::MyClass:: should cause error. Experimenting with MS Visual C++ 2017 and GNU C++ 6.2.0 I realized that any count of MyClass:: is allowed.
It is not only a theoretical question. I wanted to use SFINAE and condition compilation with existence of a sub-class. Worked good until the base class has the same name as the sub-class:
template <class T> void callWorkout() { T::SubClass::workout(); }
struct X { struct SubClass { static void workout(); }; };
struct Y { /*empty*/ };
struct SubClass { static void workout(); };
int main() {
callWorkout<X>(); // works fine - compiled
callWorkout<Y>(); // works "fine" - not compiled, no SubClass in Y
callWorkout<SubClass>(); // ooops? - still compiled, there is no 'SubClass' in SubClass
}
My question has two parts:
What is the exact semantics of MyClass::MyClass::?
How can I fix the above example not to compile callWorkout<SubClass>()? (I tried to add sizeof(typename T::SubClass) but surprisingly it compiles also for T=SubClass)
That's the injected class name of MyClass. And you can verify it's not T by simply using std::is_same_v<T, typename T::SubClass> in a SFINAE conditional.
template <class T>
auto callWorkout() -> std::enable_if_t<!std::is_same_v<T, typename T::SubClass>>
{ T::SubClass::workout(); }
If you don't need SFINAE (because you aren't trying to control overload resolution), then a static_assert with a descriptive custom message can also do nicely.

MSVC allows use of incomplete/undeclared types inside of template class method bodies?

I recently reopened a visual studio project I last worked on a year ago, and I want to get it to compile under g++. Among other issues, the compiler complains about some template code that doesn't appear legal in the first place.
Specifically, some of the template class method's instantiate Iterators for their class that are defined lower down, with no forward declarations. This would not be a problem if I was not working with templates, because the class declarations themselves are perfectly legal; it's the method bodies, which would ordinarily be in source files, which are causing problems. It seems as though templates compile differently to account for this, at least under msvc.
Sample code:
template<class T>
class ClassA : public HasIterator<T>
{
public:
Iterator<T> * GetIterator()
{
return new ClassAIterator<T>(this);
}
};
template<class T>
class ClassAIterator : public Iterator<T>
{
ClassA *foo;
public:
AggregateWrapperIterator(ClassA *foo)
{
//...
}
bool HasNext()
{
//..
}
T Next()
{
//..
}
};
I'd just add forward declarations but it get's complicated because of inheritance (there was a reason I set it up this way in the first place).
My question is this: for what reason does msvc allow this code, and does g++ have similar support?

C++ template class behaves differently for different compilers

I am working with templates in C++. Is there any difference in using templates and friend class when compiled with MSVC compiler and when using Mingw gcc compiler. My code successfully compiles and gives the desired output when compiled with MSVC but it gives error when compiled with gcc. Below is my code,
///////////Record.h/////////////////////
#include "Base.h"
class Derived1;
class Derived2;
template <class TYPE_LIST> class List;
class FRecord
{
public:
FRecord();
virtual ~FRecord();
friend class Base;
#if _MSC_VER <= 1200
friend class List<Derived1>;
friend class List<Derived2>;
#else
template <class TYPE_LIST> friend class List;
#endif
};
///////////////////////////////////////////////////////////////
///////////////////Base.h/////////////////////////////////
class Base
{
public:
Base(const HEADER *hc, const FRecord *fr);
virtual ~Base();
__inline bool IsNonValid() const;
protected:
quint32 Size;
};
/////////////////////////////////////
// Data
/////////////////////////////////////
template <class TYPE_LIST>
class Data : public TYPE_LIST
{
public:
Data(const HEADER *hc, const FRecord *fr) : TYPE_LIST(hc, fr)
{
QString val = IsNonValid() ? "Non" : "";
LOG0("Data ("<< val << " Valid)");
}
virtual ~Data()
{
LOG0("Data deleted");
}
}; // Data
///////////////////////////////////////////////////////////////////////////////////////
When compiled the above code with MSVC gives desired output but when compiled with Mingw GCC compiler it gives following error,
Base.h:1154: error: there are no arguments to 'IsNonValid' that depend on a template parameter, so a declaration of 'IsNonValid' must be available
Base.h:1553: error: 'Size' was not declared in this scope
What could be the possible solution to this problem?
Thanks in advance.
MSVC does not implement two-phase name lookup correctly. GCC is correct in reporting this error.
The cause is that names used inside a template which do not depend on the template's parameters are (should be in the case of VC) looked up when the template is defined, not when it's instantiated.
In your case, the compiler has no way of telling that IsNonValid will come from the base class, so it rightfully complains it doesn't know it. There are two possible solutions:
Qualify the access to IsNonValid, so that it's clear to the compiler it (potentially) depends on the template parameters:
QString val = this->IsNonValid() ? "Non" : "";
// or
QString val = TYPE_LIST::IsNonValid() ? "Non" : "";
Introduce the inherited name into the scope of the derived class:
template <class TYPE_LIST>
class Data : public TYPE_LIST
{
public:
using TYPE_LIST::IsNonValid;
// the rest as you had it originally
Either of these will make the name dependent and thus postpone its lookup until instnatiation, when the value of TYPE_LIST is actually known.
gcc is correct. You need to add this-> to delay lookup until instantiation time.
this->IsNonValid();
MSVC is non-conforming in that it delays all lookups until instantiation time as it doesn't properly implement two-phase name lookup.

Is it possible trigger a compiler / linker error if a template has not been instantiated with a certain type?

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 class + virtual function = must implement?

This code:
template <typename T>
struct A
{
T t;
void DoSomething()
{
t.SomeFunction();
}
};
struct B
{
};
A<B> a;
is easily compiled without any complaints, as long as I never call a.DoSomething().
However, if I define DoSomething as a virtual function, I will get a compile error saying that B doesn't declare SomeFunction. I can somewhat see why it happens (DoSomething should now have an entry in the vtable), but I can't help feeling that it's not really obligated. Plus it sucks.
Is there any way to overcome this?
EDIT 2: Okay. I hope this time it makes sence:
Let's say I am doing intrusive ref count, so all entities must inherit from base class Object. How can I suuport primitive types too? I can define:
template <typename T>
class Primitive : public Object
{
T value;
public:
Primitive(const T &value=T());
operator T() const;
Primitive<T> &operator =(const T &value);
Primitive<T> &operator +=(const T &value);
Primitive<T> &operator %=(const T &value);
// And so on...
};
so I can use Primitive<int>, Primitive<char>...
But how about Primitive<float>? It seems like a problem, because floats don't have a %= operator. But actually, it isn't, since I'll never call operator %= on Primitive<float>.
That's one of the deliberate features of templates.
If, for some reason, I would define operator %= as virtual. Or, if i'll pre-export Primitive<float> from a dll to avoid link errors, the compiler will complain even if I never call operator %= on a Primitive<float>. If it would just have fill in a dummy value for operator %= in Primitive<float>'s vtable (that raises an exception?), everything would have been fine.
Put the virtuals into selectable base classes...
struct Jumper
{
virtual void Jump =0;
};
struct Crawler
{
virtual void Crawl() =0;
};
struct JumperCrawler:
public Jumper,
public Crawler
{
};
template<typename T, typename Methods>
class ICanBoostJumpingAndCrawling :
public Methods
{
T t;
};
Now you can use ICanBoostJumpingAndCrawling with Jumper,Crawler or JumperCrawler supplied as the Methods template parameter; realizing that you need to be derived from it so that you can implement Jumping and or Crawling in a subclass.
FYI, This makes the name "ICanBoostJumpingAndCrawling" completely misleading because it may or may not be able to do that; which means it should be renamed to something like "Booster".
That's not a bug, it's a feature -- seriously. At one time, most compilers would NOT compile the code, for exactly the reason you give. They've since been updated to compile it, partly because the standard requires it.
There was feature called "Concepts" in the C++ 0x standard for quite a while that would have allowed you to specify that T needed a member named 'SomeFunction', including its return type, argument type(s), etc.
Sadly, at the last meeting of the standard committee, they decided finishing up Concepts would delay the standard longer that most people wanted to wait, so they removed them.
Though it's not nearly as good, Boost does have a Concept Checking library that can do what you're asking about.
One way to overcome this is to specialize A for template argument B and not declare DoSomething()
template <>
struct A<struct B>
{
T t;
};
Ofcourse this means that you now have to implement the entire A struct from scratch.
So the compiler should be able to work out within the compilation unit just what is in use. As soon as you start to involve multiple compilation units it no longer has the limited scope and takes the necessary step to ensure that all of the class can compile.
For exporting from a library don't force the pre export, you can ignore the warnings about not exporting the templates as long as you compile all the code with the same compiler the template will be compiled the same in all locations, only compile what is necessary within each compilation unit.
To work around the problem with virtual, then the best you can do is to defer the issue to some other class - don't put virtual in the template.
Perhaps
addition of a 'traits' portion to your template would allow a cheap way out.
use multiple inheritance to define the composite template, like using shims
ie.
template <typename T>
class Additive
{
public:
Primitive<T> &operator =(const T &value);
Primitive<T> &operator +=(const T &value);
};
template <typename T>
class Multiplicative
{
public:
Primitive<T> &operator *=(const T &value);
Primitive<T> &operator /=(const T &value);
};
template <typename T>
class Integers : public Additive<T>, public Multiplicative<T>;
I'd really go back and ask if your abstracting the right level of information for making the template.