How do lines (2) and (3) even compile in the following C++ class, given that this is a pointer, so should need -> notation to access fields (as seen in line (1))? (Source)
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
template <typename T>
class sptr_wrapper
{
private:
boost::shared_ptr<T> sptr;
public:
template <typename ...ARGS>
explicit sptr_wrapper(ARGS... a)
{
this->sptr = boost::make_shared<T>(a...);
}
explicit sptr_wrapper(boost::shared_ptr<T> sptr)
{
this->sptr = sptr; // (1)
}
virtual ~sptr_wrapper() noexcept = default;
void set_from_sptr(boost::shared_ptr<T> sptr)
{
this.sptr = sptr; // (2)
}
boost::shared_ptr<T> get_sptr() const
{
return sptr; // (3)
}
};
The line (2) is invalid. As you said, this is a pointer, we need to use -> instead of .
As the member of class template, sptr_wrapper::set_from_sptr is not required to be instantiated, until it's used. So you can add some code trying to call it, then you might get compile-errors as you expect.
This applies to the members of the class template: unless the member is used in the program, it is not instantiated, and does not require a definition.
The line (3) is valid; sptr refers to the member sptr, which has the same effect as this->sptr.
When a non-static class member is used in any of the contexts where the this keyword is allowed (non-static member function bodies, member initializer lists, default member initializers), the implicit this-> is automatically added before the name, resulting in a member access expression (which, if the member is a virtual member function, results in a virtual function call).
Would you believe that the reason this compiles is because nothing really gets compiled here?
The shown code defines a template.
A template does not become "real" until it instantiates a class. Only at that time the compiler gets a closer look at the template, and attempts to figure WTF it's doing.
Sure, when defining a template the compiler makes a half-hearted attempt to parse the template, but only barely enough to satisfy itself that the template consists of some plausibly-looking C++ code.
If you add some additional lines to the shown code you'll get the compilation errors you were yearning for:
class X {};
void foo()
{
sptr_wrapper<X> x;
boost::shared_ptr<X> y;
x.set_from_sptr(y);
}
And this produces the compilation errors you were looking for:
t.C:27:14: error: request for member ‘sptr’ in ‘(sptr_wrapper<X>*)this’, which is of pointer type ‘sptr_wrapper<X>*’ (maybe you meant to use ‘->’ ?)
27 | this.sptr = sptr; // (2)
Note that merely instantiating
sptr_wrapper<X> x;
isn't enough. You have to go full throttle and invoke the method in question, before it becomes "real" in the eyes of a C++ compiler, and it chokes on it.
It's true that I can quite think of any circumstance where "this.foo" might be valid C++ code, but I'm sure that somewhere in the 2000 pages that make up the current C++ standard, the exact details of what's going on gets spelled out in a very pedantic way.
And you might consider dropping a note to your compiler's bug tracker, a feature request to have your compiler issue a friendly warning, in advance, when it sees something like this.
Related
I want to have classes with a static data member knowing the class's complete size. This is for storing singleton instances, in case you want to know the actual use case of this.
In my naive implementation of this feature, I wanted to use a mixin class to add the special data member to my class. The mixin class would have to know the complete class (in order to know the complete class's size), so I implement it using the Curiously Recurring Template Pattern, a little bit like this:
template<class ObjectType>
class SingletonOf
{
static inline /* some type same size as ObjectType */ instance_memory;
public:
void *operator new(std::size_t)
{
return &instance_memory;
}
void operator delete(void *)
{
}
};
class foo : public SingletonOf<foo> // CRTP used here, to let SingletonOf know foo
{
// foo data members...
// foo member functions...
};
void bar() {
foo *p = new foo; // calls SingletonOf<foo>::operator new and returns the instance memory
}
Cute, right? Well, I learned that the following in C++20 is ill-formed (note: in all the code samples below, the class foo and the function bar() do not change. Also I will not keep writing the empty definition of SingletonOf::operator delete, because you can remember that it's there):
template<class ObjectType>
class SingletonOf
{
static char inline instance_memory[sizeof(ObjectType)]; // syntax error: incomplete type
public:
void *operator new(std::size_t) { return instance_memory; }
...
Now, we will all agree the reason why that is ill-formed - and I am not complaining, just informing - is that ObjectType is foo, and until the closing brace of foo, foo is an incomplete type. And, obviously, sizeof cannot be called on incomplete types. So, I am fine with that. However, the following using a nested class-template does work - at least according to clang++ in c++20 mode, I think?
template<class ObjectType>
class SingletonOf
{
template<class CompleteObjectType>
struct InstanceMemory
{
static char inline instance_memory[sizeof(CompleteObjectType)];
};
public:
void *operator new(std::size_t) {
return InstanceMemory<ObjectType>::instance_memory;
}
...
Now my question is: why does that work? Or, let's start with the more fundamental question: does that work, actually? As of this writing, just to be clear, I have not verified that bar() actually calls the intended operator new and returns the foo-sized instance memory. Probably, should do that. But I'm busy. What I do know at this time, is that my clang++ in c++20 mode compiles it. This compilation includes compiling the function bar(), which allows me to be certain it instantiates the template. So that is to back up my contention that the compiler is accepting it. There are no errors or warnings give, just an output object file.
If I am right that this second code is well-formed, then it looks like ObjectType (= foo) in the body of operator new in the second code sample, is considered a complete type. How did that happen?
This isn’t really any different from having InstanceMemory defined in a namespace: until it is instantiated, its template argument need not be complete. This separation works because it removes the presumption that you should be able to use decltype(SingletonOf::instance_memory) immediately after declaring it.
When SingletonOf<ObjectType> is being instantiated, ObjectType is incomplete. That's why you can't get the size of it.
However, the member function bodies of SingletonOf work as if they are placed just after the type. And those functions get instantiated at a point when ObjectType is complete. This is why ObjectType is complete and visible to member functions of SingletonOf<ObjectType>.
Your inner struct InstanceMemory is itself a template. And you instantiate it within a member function of the outer template. Since that member function sees ObjectType as complete, so too does InstanceMemory<ObjectType>.
All you have to do is make sure to instantiate InstanceMemory<ObjectType> at a point where ObjectType is complete.
Is it possible (and is it a good idea) to conditionally define methods for some container class (template<typename ThingType> class Container) depending on the type of its elements? I first thought it was possible after reading about std::enable_if, but now I am not certain I understand.
Below is my attempt (click here to run on ideone). In the case that std::is_base_of<ThingBase, ThingType>::value is false, a return type for p will not be defined. I figured the compiler would just instantiate the object of a class without that method. But it turns out it doesn't compile.
Is there another tool for the job? Or should I write two Container-like classes that have different behavior depending on what ThingType is? Or maybe this is a job for a specialization.
#include <iostream>
#include <type_traits>
#include <vector>
class ThingBase {
public:
virtual void printHi() = 0;
};
class Thing : public ThingBase
{
void printHi(){
std::cout << "hi\n";
}
};
template<typename ThingType>
class Container{
private:
std::vector<ThingType> m_things;
public:
typename std::enable_if<std::is_base_of<ThingBase, ThingType>::value>::type p()
{
m_things[0].printHi();
};
};
int main() {
//Container<Thing> stuff; // works!
Container<int> stuff; // doesn't work :(
return 0;
}
Edits:
The error message from the compiler is
prog.cpp: In instantiation of ‘class Container<int>’:
prog.cpp:36:17: required from here
prog.cpp:26:78: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
typename std::enable_if<std::is_base_of<ThingBase, ThingType>::value>::type p()
#StoryTeller - Unslander Monica I don't intend for this method to be overloaded. I want it to be available to the end user whenever it makes sense for it to be available. There will only be one of these p methods, and it should take only one (relatively simple) signature.
I don't intend for this method to be overloaded. I want it to be available to the end user whenever it makes sense for it to be available. There will only be one of these p methods, and it should take only one (relatively simple) signature.
This simplifies the exercise quite a bit. The solution is... to do nothing special.
void p() {
m_things[0].printHi();
}
When a class template is implicitly instantiated, only the declarations of member function are instantiated along with it. Definitions are not instantiated until an attempt is made to use the member.
So you do not need to do anything special. The error will happen if it's used when it cannot be used.
If still you wish to ensure derivability, and produce a descriptive error in that case, you can add a static_assert to the member function body. Simply use the is_base_of test for a condition, and add a nice string to accompany it.
This is a common approach when writing generic utilities. SFINAE's primary purpose on the other hand is to control overload resolution. But you aren't doing it here.
I have the following class:
template <class T>
class BeliefSet : public Belief<T>
{
private:
std::vector<T> m_Facts;
public:
void RemoveFact(const T Fact)
{
m_Facts.remove(Fact);
}
};
This works fine. However, I want to derive another class from BeliefSet and override this method RemoveFact(), thus I changed the code shown above to the following:
/* Rest of this class has not been changed. */
virtual void RemoveFact(const T Fact)
{
m_Facts.remove(Fact);
}
Now as soon as I compile I get this error:
error C2039: 'remove': is not a member of 'std::vector<std::string,std::allocator<_Ty>>'
Any ideas what I am doing wrong here?
This works fine.
No, it doesn't. std::vector has no member function remove(). However, class template member functions aren't eagerly instantiated. It's likely that you simply never invoked RemoveFact(), so you never had to run into this problem. This "lazy" instantiation is very important - it lets you write and use class templates that have conditionally valid operators without writing loads of SFINAE junk (e.g. I can use std::map fine with non-default-constructive value types, I just can't use operator[]).
When you made the function virtual, as you as inherit from it, it is likely that your compiler attempted to instantiate the function at that point (it is unspecified whether an implementation does so - yours apparently does). Since this function is ill-formed, you get the error via the virtual function instantiation instead of normal function instantiation.
Either way, the function is broken and you want:
void RemoveFact(const T& Fact)
{
m_Facts.erase(
std::remove(m_Facts.begin(), m_Facts.end(), Fact),
m_Facts.end());
}
I would like to know, when someone gives you a template for a default constructor in C++ and in the parameter there is a series of unnamed variables that somehow are assigned values. What does this mean?
Is this legal?
How can one access these variables?
Example I received:
IntSet::IntSet(int = -1, int = -1, int = -1, int = -1); //default constructor
I would appreciate any answers that clarify this use!
It's perfectly legal to not name the arguments in the declaration or in the definition of a function. It's also perfectly legal to use different names for a given argument in the declaration and definition.
Note that if a parameter that is not named in the definition is not accessible. Why do this? A lot of compilers can be made to complain about unused arguments. Most compilers won't complain if the function definition doesn't name those unused arguments.
About unnamed parameters in a declaration, which is the topic of this question: Just because doing this is legal doesn't necessarily mean it's a good practice. Those unnamed arguments in a function declaration might be fine for a compiler, but they aren't fine for a human reader. No name = zero communication. The documentation and header file should contain everything that an external user needs to know regarding how to use the class. RTFM and maybe RTFH (read the fine manual / read the fine headers). That "F" word ("fine") in RTFM and RTFH takes on a different meaning in RTFC.
Those unnamed arguments in a header are almost inevitably coupled with poor documentation. As an external user, this forces me to read the function's definition to understand how to use a function. RTFC. It is not fine when an external user has to read the implementation to determine what is going on.
That means that if you call it without passing parameters, the parameters will take the values you passed.
So if you call
IntSet* i = new Intset();
would be equivalent to calling
Intset* i = new IntSet(-1,-1,-1,-1)
About the unnamed part. I would assume because it is part of a library that uses templates. The nameless parameters are not used, but are there so it matches the signature of another class that may need them. In the case that it needs them, it will just pass -1 by default.
You can take a look at this link for an example:
http://compgroups.net/comp.lang.c++/unnamed-formal-parameter/1004784
I am copying the example from the above reference here, to make the case for using such a construct in an useful way
For instance
class A
{
public:
A(void* = 0) {} // unused parameter
};
class B
{
public:
B(void* p) : pp(p) {} // used parameter
private:
void* pp;
};
template <class T>
class C
{
public:
static T* create(void* p = 0) { return new T(p); }
};
int main()
{
A* a = C<A>::create();
B* b = C<B>::create("hello");
}
C::create would not compile unless A::A had a parameter even though it is
not used.
I'm trying to do a base template class which parameter T must be a structure.
When I use a variable declared as being of type T (both in the template class as in a class that extends it defining T) GCC fails to compile it:
GCC error: invalid use of incomplete
type ‘struct x'
Despite it working on VC I understand that it doesn't work because it shouldn't because the compiler isn't aware per the standard of the types that T represent.
Is there a way of making explicit that the type must be a structure?
What I'm doing in the code that works in VC is:
In the base class:
T* x
new T
sizeof(T)
In those that extend it:
x->member
Edit: I tried to take the relevant code. Here it is:
struct SomeStructureType
{
int memberA;
int memberB;
}
template <typename T> class Base
{
protected:
T* s;
void addMember(string name,void* offset);
Base()
{
s = new T;
}
};
class Extender : public Base<SomeStructureType>
{
public:
Extender()
{
addMember("memberA",&s->memberA);
}
}
Most (if not all) times the compiler complains about using an 'incomplete' type the problem resides in trying to use a forward declared class that has not been completely defined.
There are just so many things you can do with an incomplete type: define functions that take or return the type or references to it, define reference or pointer variables of that type... and others you cannot do: define variables of that type, create an object of the type, call any method or request any attribute from the type...
The question in the title can be dismissed; C++ classes and structures cannot be distinguished other than by source code inspection.
The explanation is quite confusing. There's apparently a message about struct x yet the example code contains not a single x. That tells me that you're not careful about matching up errors and source code. Once you do that, you often don't need StackOverflow anymore - you'll see the problem yourself.
There is nothing wrong with the code you've posted other than two missing semicolons after class/struct definitions: http://codepad.org/yfbHa8sO
The problem isn't related to the fact that T must be a structure. The problem is in that one of the structures (that I'm using in my code but was not created by me) is said to be incomplete by gcc. Anyway, I removed the class that uses this structure and other classes compile with the same base class. So, is up to me to fix it and what I assumed about the problem was wrong.