I didn't expect this to compile but it does. I'm wondering if this is guaranteed to happen or whether it's just compiler-specific. I'm wondering why 'OSInterface::handleOSEvents()' can see the 'InputHandler' class and its member function. If OSInterface is an ordinary class then it doesn't compile, the order of the class definitions must be swapped.
template <typename input_handler_t>
class OSInterface
{
public:
void readOSEvents()
{
input_handler_t::handleKeyDown(5);
}
};
struct InputHandler
{
static void handleKeyDown(int a) {};
};
int main()
{
OSInterface<InputHandler> os;
os.readOSEvents();
}
Edit: I was thinking the compiler must be doing something special with it, because if it instantiates the template class in the order that it's declared then it shouldn't be able to see 'InputHandler' and call its member function. On the other let's say that it instantiates the class right at the bottom of the .cpp then it would be able to see 'InputHandler' but I wouldn't be able to create an object of that class in main().
I'm wondering why 'OSInterface::handleOSEvents()' can see the 'InputHandler' class and its member function.
There is no OSInterface::handleOSEvents() in the example. I assume that you mean OSInterface::readOSEvents().
Because OSInterface is instantiated after InputHandler was defined.
I'm wondering if this is guaranteed to happen or whether it's just compiler-specific.
The program is well-formed. The program will compile with all standard conforming language implementations.
Related
I am using VS Express 2013 trying to compile a c++ project. I've created a template class with some functions. The class and its functions are all in one header file. I've included the file, I've used the class, I've called functions from it, and despite all that visual studio won't compile the classes' functions that I'm not using. I've turned off all optimizations. Do I HAVE to use a function that I've written just to see that it compiles or not?
Here is the function:
void remove(ID id)
{
sdfgsdfg456456456456sfdsdf
}
The function shouldn't compile. And indeed the project won't compile if I do use this function, but if I don't use the function the project will compile, even if I use other functions from within this class.
Is there a fix to this? Will the same thing happen if I implement the function in a .cpp file?
Edit: I neglected to mention it is a template class. I've added that information in.
As revealed in comments, the reason this is happening is because remove() is a function in a class template. The compiler only instantiates template code if it is actually used; if you don't call remove(), it can have all the syntax errors you want and nobody will complain.
More formally, § 14.7.1 of the standard states (emphasis mine):
The implicit instantiation of a class template specialization causes
the implicit instantiation of the declarations, but not the
definitions or default arguments, of the class member functions
And later in the same section:
An implementation shall not implicitly instantiate a function
template, a member template, a non-virtual member function, a member
class, or a static data member of a class template that does not
require instantiation.
(the word "implicit" is key here; if you use explicit template instantiation, the compiler will immediately try to instantiate all members using the indicated type(s) and fail if any doesn't compile)
This is not just an optimization; you can exploit this behavior to instantiate class templates with types that only support a subset of the template's operations. For example, suppose you write a template class that will be used with types that support a bar() operation, and in addition, some will also support baz(). You could do this:
template<typename T>
class Foo
{
private:
T _myT;
public:
void bar()
{
_myT.bar();
}
void baz()
{
_myT.baz();
}
};
Now suppose you have these too:
struct BarAndBaz
{
void bar() {}
void baz() {}
};
struct BarOnly
{
void bar() {}
};
This will compile and run just fine:
void f()
{
Foo<BarAndBaz> foo1;
foo1.bar();
foo1.baz();
Foo<BarOnly> foo2;
foo2.bar();
// don't try foo2.baz()!
// or template class Foo<BarOnly>!
}
I have two test cases of a class having a static member instance. The first uses non-templated samples, while the second relies on generic object types.
The dilemma is simple: the constructor of the static member gets called before the main function (as it should), but only for the specific object types. The generic types do not exhibit the same behaviour. As the matter of fact, the constructor isn't compiled at all. It seems the compiler decided to completely overlook it as a means of (not completely justified) optimization.
I would like to know what is happening and what can be done to make it work in the most elegant way possible. I presume the obvious answer would be: use that static member somewhere in the code. I'd like not to do that, as the specific type case works without making use of that static member, apart from performing some "work" in its constructor.
The code samples:
//////////////////////////////////////////////
// Specific case
//////////////////////////////////////////////
class CPassive
{
public:
CPassive()
{
printf(" passively called ");
}
};
class CActive
{
private:
static CPassive ms_passive;
};
CPassive CActive::ms_passive;
///////////////////////////////////////////////////////////
// GENERIC TYPES
///////////////////////////////////////////////////////////
class CSample
{
public:
CSample()
{
printf("sample ");
}
};
template <typename T>
class CGenericPassive
{
public:
CGenericPassive()
{
T sample;
printf(" generic passive .. ");
}
private:
};
template <typename T>
class CGenericActive
{
private:
static CGenericPassive<T> ms_passive;
};
template<typename T>
CGenericPassive<T> CGenericActive<T>::ms_passive;
int main(int argc, char** argv)
{
CActive activeExample;// instantiates the static member
CGenericActive<CSample> activeExample; // obliterates the static from the class def.
}
Each (non-virtual) member of each class template you want instantiated needs to be referenced from non-template code, directly or indirectly. It is not enough to instantiate the class itself.
This is governed by the standard 14.7.1/2:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
In your case it is enough to reference the member from CGenericActive constructor (you need to write this constructor obviously), like this:
CGenericActive()
{
// just reference it so it gets instantiated
(void)ms_passive;
}
Full live example.
If I have a class template and I use a smart pointer to a dynamically allocated instance of a specialized instance, does that cause the entire class template to be defined by the complier or will it also wait for a member function to be called from the pointer before it is instantiated?
template <class T>
class Test {
public:
void nothing();
void operation();
static const int value;
};
template <class T>
const int Test<T>::value = 100;
template <class T>
void Test<T>::nothing() {
/* invalid code */
int n = 2.5f;
}
template <class T>
void Test<T>::operation() {
double x = 2.5 * value;
}
int main() {
std::unique_ptr<Test<int>> ptr = new Test<int>(); // mark1
ptr->operation(); // mark2
return 0;
}
Does the entire class template get instantiated at mark1?
If not does that mean this code will compile correctly and the member function Test::nothing() not be instantiated?
Does the entire class template get instantiated at mark1?
Yes. The class template is implicitly instantiated — only the class template, not all its members.
If not does that mean this code will compile correctly and the member function Test::nothing() not be instantiated?
The not doesn't imply that, rather if nothing() is not used, it is not instantited.
The full answer to this probably depends highly on what compiler you are using.
At //mark1, the compiler will notice that at least portions of the Test<int> class need to instantiated. Whether or not it does it right then, or in a later phase, is up to the compiler designer.
At //mark2, Test<int>.operation() is obviously needed, it is either marked for later instantiation or created on the spot, again depending on what the compiler designers decided.
Since Test<int>.nothing() is never referenced, the compiler has the freedom to instantiate it or not. Some older compilers blindly instantiated the entire class, but I suspect the majority of modern compilers will only instantiate what they can prove to be necessary (or at least that they can't prove is not necessary). Again, though, where that happens within the compiler depends on the way the compiler designers built the compiler.
So as it turns out for the compiler I'm using (MS Visual C++), my supposition was correct that, for the code as presented in the question, the class template member instantiation would not take place at //mark1 but rather at //mark2 and Test<int>.nothing() would not be created by the compiler.
However, it seems I left out a critical part of the issue that I was experiencing. My actual class was a part of a virtual hierarchy, and according to the MSDN help library all virtual members are instantiated at object creation. So in the example above, if both member functions, i.e. operation() and nothing(), are virtual then at //mark2 the compiler would try to generate code for both functions and the validation of nothing() would fail.
http://msdn.microsoft.com/en-us/library/7y5ca42y.aspx
http://wi-fizzle.com/howtos/vc-stl/templates.htm#t9
I have following piece of code:
It compiles without problems under gcc-3.4, gcc-4.3, intel compiler, but fails under MSVC9.
MSVC tells "use of undefined type c_traits<C>, while compiling class template member function void foo<C>::go(void) with C=short.
The point it the compiler tries to install unused member function of unused class, because
this class is just not used at all.
I can work-around the issue by specializing entire class foo instead of specializing
its member function. But the point it that specializing entire class is little bit problematic for me for different reasons.
The big question: what is right?
Is my code wrong and gcc and intel compiler just ignore the issue because they do not install foo fully, or
The code is correct and this is bug of MSVC9 (VC 2008) that it tries to install unused member functions?
The code:
class base_foo {
public:
virtual void go() {};
virtual ~base_foo() {}
};
template<typename C>
struct c_traits;
template<>
struct c_traits<int> {
typedef unsigned int_type;
};
template<typename C>
class foo : public base_foo {
public:
static base_foo *create()
{
return new foo<C>();
}
virtual void go()
{
typedef typename c_traits<C>::int_type int_type;
int_type i;
i=1;
}
};
template<>
base_foo *foo<short>::create()
{
return new base_foo();
}
int main()
{
base_foo *a;
a=foo<short>::create(); delete a;
a=foo<int>::create(); delete a;
}
Both compilers are right here; the behavior for your case is unspecified. ISO C++ 14.7.1[temp.inst]/9:
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.
The reasoning for this is fairly simple: a virtual function requires a vtable entry, and with virtual dispatch, it may be tricky for the compiler to determine whether a given virtual function is actually called or not. Therefore, ISO C++ permits the compilers to do such advanced analysis for the sake of generating smaller code, but does not require it of them - so, as a C++ programmer, you should always assume that all virtual functions will always be instantiated.
The removal of unused functions will occur at linking not at compilation where you are having your error. MSVC may not know who amongst all the compilation units being compiled who will ultimately call that method. It can't know until compilation is complete and until linking occurs. Naturally different compilers may be smarter about this, but I suspect this may be what is happening.
I suspect your specific compiler errors sounds like it is caused by you having only forward declared
template<typename C>
struct c_traits;
you have not fully specified the class. Did you try something as simple as:
template<typename C>
struct c_traits
{
// some default/dummy int type
};
I suspect this would at least stop the compiler from complaining.
EDIT
this is generally wrong for class
templates. Member functions of class
templates aren't supposed to be
compiled (and any errors in their
bodies aren't supposed to be
triggered) unless they're instantiated
The template is instantiated in this case in the form of:
foo<short>
The compiler will treat this as any other class who's methods have potential for external linkage. I haven't heard any special language rule that says that external linkage doesn't apply to templates...?
I have a template class defined like so:
template <class T>
class Command {
public:
virtual T HandleSuccess(std::string response) = 0;
virtual std::string FullCommand() const = 0;
// ... other methods here ...
};
Will C++ allow me to create a non-template subclass of a template class? What I mean is can I do something like this:
class NoopCommand : public Command<NoopResult> {
public:
NoopResult HandleSuccess(std::string response);
std::string FullCommand() const;
// ... other methods here ...
};
As is that is not working for me because it says the following virtual functions are undefined:
T admix::Command<T>::HandleSuccess(std::string) [with T = admix::NoopResult]
std::string admix::Command<T>::FullCommand() const [with T = admix::NoopResult]
How can I specifically define them for the given T?
As we figured out in IRC, that was because you have
Made your functions non-pure
Sliced the derived object part. So the base class functions were called because the object wasn't a complete derived object anymore.
(Below follows my suspicion on earlier versions of your question - i keep it for further consideration and to keep the comments meaningful)
I think the issue here is that the compiler is free to instantiate any virtual function member of a class template even if it's not used (i.e not called). Instantiating a function will need a function definition to be provided. Try to add this in the header, where the compiler will find them and instantiate a definition from:
template<typename T>
T Command<T>::HandleSuccess(std::string response) { /* put some default action ... */ }
template<typename T>
std::string Command<T>::FullCommand() const { /* put some default action ... */ }
C++ Standard 14.7.1/9:
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual
member function, a member class or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.
"virtual functions are undefined" means you have not defined the function bodies of NoopCommand::HandleSuccess and NoopCommand::FullCommand.
The following should solve your problem.
class NoopCommand : public Command<NoopResult> {
public:
NoopResult HandleSuccess(std::string response) {}
std::string FullCommand() const {}
// ... other methods here ...
};
Or you you have a NoopCommand.cpp, make sure it's included in your build process.
The pattern you use is widely known as the "Curiously Recurring Template Pattern". so, yes, you can do that.
I can't think of a reason why it does not compile.
The code you gave compiles for me, without errors (after adding a struct NoopResult { };). Maybe there's a problem in the code you left out?
litb found the solution on ##c++ last night.
The issue was I was passing a NoopCommand to a function like this:
void SendCommand(Command<T> command);
When I should have made the signature this:
void SendCommand(Command<T>& command);
Making that change allows everything to compile.