case of template member function specialization that compiles on msvc, not others - c++

[ EDIT ] I changed the title from works to compiles since it turns out that it doesn't truly work after all (thanks #bogdan for the comments). I added code at the end of the post showing why and how.
The second part of the question still stands - is there a way to "fix" it? The crux of the matter is having a virtual function Observe in a base template<int N> class X be rerouted to a templated function Observe<N> in classes derived from X<N>, without requiring any supporting code in X.
For an example of how it can be done by requiring X to cooperate see this answer to the other question (which basically requires that Observe<N> be declared into the most derived class).
While looking at this other question Choosing which base class to override method of I found out that the following snippet compiles cleanly on vc++ 2015 (with /W4 /Za) and returns the expected output, yet fails to compile on gcc-5.1 and clang 3.7 (tried at ideone.com).
I am aware that specialization of template functions has many pitfalls, but I am still curious which letter of the C++ standard applies in this case, and - in the likely case that the code is not fully compliant - whether there is an easy way to "fix" it.
#include <iostream>
using std::cout;
using std::endl;
typedef int Parameter;
class Observer
{
public:
virtual void Observe(Parameter p) = 0;
};
class TaggedDispatch
{
public:
template<size_t Tag> void TObserve(Parameter p);
};
template<size_t Tag>
class TaggedObserver : virtual public TaggedDispatch, public Observer
{
public:
virtual void Observe(Parameter p) override
{ TObserve<Tag>(p); }
};
class Thing : public TaggedObserver<0>, TaggedObserver<11>
{ };
template<> void Thing::TObserve<0>(Parameter p)
{ cout << "Parent # 0, Parameter " << p << endl; }
template<> void Thing::TObserve<11>(Parameter p)
{ cout << "Parent # 11, Parameter " << p << endl; }
int main(int, char **)
{
Thing test;
test.TObserve<0>(101);
test.TObserve<11>(999);
return 0;
}
Output when compiled with vc++ 2015.
Parent # 0, Parameter 101
Parent # 11, Parameter 999
Compile errors fromgcc-5.1
prog.cpp:29:17: error: template-id 'TObserve<0>' for 'void Thing::TObserve(Parameter)' does not match any template declaration
template<> void Thing::TObserve<0>(Parameter p)
^
prog.cpp:32:17: error: template-id 'TObserve<11>' for 'void Thing::TObserve(Parameter)' does not match any template declaration
template<> void Thing::TObserve<11>(Parameter p)
Compile errors from clang 3.7.
prog.cpp:22:36: warning: 'override' keyword is a C++11 extension [-Wc++11-extensions]
virtual void Observe(Parameter p) override
^
prog.cpp:29:24: error: no function template matches function template specialization 'TObserve'
template<> void Thing::TObserve<0>(Parameter p)
^
prog.cpp:32:1: error: extraneous 'template<>' in declaration of variable 'TObserve'
template<> void Thing::TObserve<11>(Parameter p)
^~~~~~~~~~
prog.cpp:32:24: error: variable has incomplete type 'void'
template<> void Thing::TObserve<11>(Parameter p)
^
prog.cpp:32:32: error: expected ';' at end of declaration
template<> void Thing::TObserve<11>(Parameter p)
^
;
prog.cpp:32:32: error: expected unqualified-id
1 warning and 5 errors generated.
[ EDIT ] It doesn't truly work in vc++ 2015 after all. What appears to happen is that the compiler allows the void Thing::TObserve<0> definition, but internally maps it to void TaggedDispatch::TObserve<0>. This becomes obvious if adding another derived class e.g.
class Other : public TaggedObserver<0>
{ };
template<> void Other::TObserve<0>(Parameter p)
{ cout << "Parent # 00, Parameter " << p << endl; }
Then the vc++ 2015 compile fails with the error message:
error C2766: explicit specialization; 'void TaggedDispatch::TObserve<0>(Parameter)' has already been defined

MSVC is wrong to accept the code; Clang and GCC (and EDG) are right to reject it.
This case is similar to the one in this question, but it involves a different syntactic construct (and different code paths in the compilers, yielding different Standard conformance results, with only EDG being consistent).
In template<> void Thing::TObserve<0>(Parameter p), Thing::TObserve<0> is a declarator-id, with Thing:: being a nested-name-specifier. [8.3p1] says:
[...] When the declarator-id is qualified, the declaration shall refer
to a previously declared member of the class or namespace to which the
qualifier refers (or, in the case of a namespace, of an element of the
inline namespace set of that namespace (7.3.1)) or to a specialization
thereof; the member shall not merely have been introduced by a
using-declaration in the scope of the class or namespace nominated by
the nested-name-specifier of the declarator-id. [...]
So, you have to use template<> void TaggedDispatch::TObserve<0>. As noted in the question, using Thing:: could create the false impression that you can provide different explicit specializations of TObserve for different derived classes, which is not the case. There's only one TObserve member function template, the one declared in TaggedDispatch, and all such explicit specializations (and implicit or explicit instantiations, and partial specializations) are "attached" to that declaration.
One solution to make things work the way you expect is to declare an Observe member function template in each derived Thing-like class, possibly providing explicit specializations for relevant Tags if necessary, and let specializations of the template be automatically wired up to the corresponding Observer interface instance using CRTP:
#include <iostream>
#include <cstddef>
using Parameter = int;
struct Observer
{
virtual void Observe(Parameter p) = 0;
};
template<std::size_t Tag> struct TaggedObserver : Observer { };
template<class Derived, std::size_t Tag> struct CrtpObserver : TaggedObserver<Tag>
{
void Observe(Parameter p) override
{
static_cast<Derived*>(this)->template Observe<Tag>(p);
}
};
struct Thing : CrtpObserver<Thing, 0>, CrtpObserver<Thing, 1>
{
template<std::size_t N> void Observe(Parameter p);
};
template<> void Thing::Observe<0>(Parameter p)
{
std::cout << "Interface #0, Parameter " << p << '\n';
}
template<> void Thing::Observe<1>(Parameter p)
{
std::cout << "Interface #1, Parameter " << p << '\n';
}
int main()
{
Thing test;
TaggedObserver<0>* p0 = &test;
TaggedObserver<1>* p1 = &test;
p0->Observe(7);
p1->Observe(3);
}
This places the implementations of the Observer interface in Thing where they belong, while requiring minimal plumbing in each derived class - not much more than what you would have to do anyway if you could separately override each Observer::Observe directly.

Related

C++ name lookup affected by declaration of a template method

I don't understand the need for the static_cast in the following C++ code snippet (tested with GCC-4.7):
#include <cstdio>
class Interface
{
public:
virtual void g(class C* intf) = 0;
virtual ~Interface() {}
};
class C
{
public:
void f(int& value)
{
printf("%d\n", value);
}
void f(Interface* i)
{
i->g(this);
}
template <typename T>
void f(T& t);
//void f(class Implementation& i);
};
class Implementation : public Interface
{
public:
Implementation(int value_) : value(value_) {}
void g(C* intf)
{
intf->f(value);
}
private:
int value;
};
int main()
{
C a;
Implementation* b = new Implementation(1);
//a.f(b); // This won't work: undefined reference to `void C::f<Implementation*>(Implementation*&)'
a.f(static_cast<Interface*>(b));
delete b;
return 0;
}
If I omit the static_cast, I get a linker error because it wants to use:
template <typename T>
void f(T& t);
instead of:
void f(Interface* i);
On the other hand, if I replace the templated method with the following (commented out in the above snippet):
void f(class Implementation& i);
then I don't get errors and I can see that the "correct" method is called at run-time (that is:
void f(Interface* i);
).
Why does the declaration of the template method affect name lookup?
Many thanks in advance,
When performing overload resolution for a.f(b), the compiler notes two facts:
First, You are trying to call f with an lvalue of type Implementation*.
Second, three functions are in the overload set: C::f(int&) and C::f(Interface*) and C::f<Implementation*>(Implementation*&). Note that the template is included since its template parameter could be deduced from the argument it is being called with.
Now the compiler starts to check which function fits "best":
C::f(int&) cannot be called with this argument at all.
C::f(Interface*) can be called, but requires one standard conversion (pointer to derived -> pointer to base)
C::f<Implementation*>(Implementation*&) can be called without any conversions
Thus, the template quite simply fits best. However, as you did not define an implementation for the template, the linker later on bugs out with the error message that it cannot find the function you are trying to call.

Clang does not find function instantiated after function definition in template context

I have been experimenting with code derived from the "C++ Seasoning" presentation by Sean Parent, and have boiled my problem down to the following code:
#include <memory>
struct container {
struct concept {
virtual ~concept() {}
virtual void foo_() = 0;
};
template <class T> struct model : concept {
model (T x) : data_(x) {}
void foo_() {
foo(data_); // Line 13
}
T data_;
};
template <class T>
container(T x) : self_(new model<T>(x)) {} // Line 20
std::unique_ptr<concept> self_;
friend void foo(container &c) { c.self_->foo_(); }
};
void foo(int i) // Line 27
{
}
int main()
{
int i = 5;
container c(i); // Line 34
foo(c);
}
The problem I have is that this code that compiles with g++, and yet not with Clang.
Clang gives me the following error messages:
prio.cpp:13:13: error: call to function 'foo' that is neither visible in the
template definition nor found by argument-dependent lookup
foo(data_);
^
prio.cpp:20:32: note: in instantiation of member function
'container::model<int>::foo_' requested here
container(T x) : self_(new model<T>(x)) {}
^
prio.cpp:34:15: note: in instantiation of function template specialization
'container::container<int>' requested here
container c(i);
^
prio.cpp:27:6: note: 'foo' should be declared prior to the call site
void foo(int i)
^
My understanding is that overload resolution during templates occurs at the point of instantiation. In this case, that is line 34 (as marked above.) At this point, the global "foo" function is known. And yet, it appears not to resolve.
Note for posterity: This was with Clang built from trunk on 14/Jan/14
Is this a bug in Clang then, or with g++?
Gcc is wrong in this case, the code should not compile; but this is completely unrelated to the template. Friend declarations are particular in that they provide a declaration for a namespace level entity, but the declaration is not visible for normal lookup until a namespace declaration is also seen by the compiler.
Consider the simplified example:
struct X {
friend void f(int); // [1]
void g() { f(1); } // [2]
};
void h() { f(1); } // [3]
void f(int); // [4]
void i() { f(1); } // [5]
The friend declaration [1] inside the X class provides a declaration for a namespace level function f taking an int, but that declaration is not visible at namespace level until a namespace level declaration is present in [4]. Both [2] and [3] will fail to compile, although [5] will compile since at that point the compiler will have parsed the function declaration.
So how can the declaration in [1] be used by the compiler to resolve a call? In this particular case never. The friend declaration can only be found by argument dependent lookup, but ADL will only look inside X if one of the arguments to the function call is of type X. In this case, the function does not have any argument X, so lookup will never use the friend declaration for anything other than lifting the restrictions of access to the variables of X.
That is:
struct Y {
friend void f(int) {}
};
Without a latter namespace level declaration for f will declare and define a function that cannot be used anywhere in your program (lookup won't ever find it).
The simple workaround for your problem is to provide a declaration for the function at namespace level before the definition of the class:
#include <memory>
void foo(int);
struct container { // ...

Inlining causes specialized member function of template class overriding virtual functions to get overlooked

I wanted to share a strange example with you guys that I stumbled upon and that kept me thinking for two days.
For this example to work you need:
triangle-shaped virtual inheritance (on member function getAsString())
member function specialization of a template class (here, Value<bool>::getAsString()) overriding the virtual function
(automatic) inlining by the compiler
You start with a template class that virtually inherits a common interface - i.e. a set of virtual functions. Later, we will specialize one of these virtual functions. Inlining may then cause our specilization to get overloooked.
// test1.cpp and test2.cpp
#include <string>
class ValueInterface_common
{
public:
virtual ~ValueInterface_common() {}
virtual const std::string getAsString() const=0;
};
template <class T>
class Value :
virtual public ValueInterface_common
{
public:
virtual ~Value() {}
const std::string getAsString() const;
};
template <class T>
inline const std::string Value<T>::getAsString() const
{
return std::string("other type");
}
Next, we have to inherit this Value class and the interface in a Parameter class that itself needs to be templated as well:
// test1.cpp
template <class T>
class Parameter :
virtual public Value<T>,
virtual public ValueInterface_common
{
public:
virtual ~Parameter() {}
const std::string getAsString() const;
};
template<typename T>
inline const std::string Parameter<T>::getAsString() const
{
return Value<T>::getAsString();
}
Now, do not(!) give the forward declaration of a specialization for Value for type equaling bool ...
// NOT in: test1.cpp
template <>
const std::string Value<bool>::getAsString() const;
But instead simply give its definition like this ...
// test2.cpp
template <>
const std::string Value<bool>::getAsString() const
{
return std::string("bool");
}
.. but in another module (that's important)!
And finally, we have a main() function to test what is happening:
// test1.cpp
#include <iostream>
int main(int argc, char **argv)
{
ValueInterface_common *paraminterface = new Parameter<bool>();
Parameter<int> paramint;
Value<int> valint;
Value<bool> valbool;
Parameter<bool> parambool;
std::cout << "paramint is " << paramint.getAsString() << std::endl;
std::cout << "parambool is " << parambool.getAsString() << std::endl;
std::cout << "valint is " << valint.getAsString() << std::endl;
std::cout << "valbool is " << valbool.getAsString() << std::endl;
std::cout << "parambool as PI is " << paraminterface->getAsString() << std::endl;
delete paraminterface;
return 0;
}
If you compile the code as follows (I placed it into two modules named test1.cpp and test2.cpp where the latter only contains the specialization and necessary declarations):
g++ -O3 -g test1.cpp test2.cpp -o test && ./test
The output is
paramint is other type
parambool is other type
valint is other type
valbool is bool
parambool as PI is other type
If you compile with -O0 or just -fno-inline - or also if you do give the forward declaration of the specialization - the result becomes:
paramint is other type
parambool is bool
valint is other type
valbool is bool
parambool as PI is bool
Funny, isn't it?
My explanation so far is: Inlining is at work in the first module (test.cpp). The required template functions get instantiated but some just end up being inlined in the calls to Parameter<bool>::getAsString(). On the other hand, for valbool this did not work but the template is instantiated and used as a function. The linker then finds both the instantiated template function and the specialized one given in the second module and decides for the latter.
What do you think of it?
do you consider this behavior a bug?
Why does inlining work for Parameter<bool>::getAsString() but not for Value<bool>::getAsString() although both override a virtual function?
I speculate that you have an ODR problem, so there is little sense in guessing why some compiler optimization behaves differently from another compiler setting.
In essence, the One Definition Rule states that the same entity should
have the exact same definition throughout an application, otherwise the
effects are undefined.
The fundamental problem is that the code that doesn't see the specialized version of your class template member function might still compile, is likely to link, and sometimes might even run. This is because in the absence of (a forward declaration of) the explicit specialization, the non-specialized version kicks in, likely implementing a generic functionality that works for your specialized type as well.
So if you are lucky, you get a compiler error about missing declarations/definitions, but if you are really unlucky you get "working" code that does not what you intend it to do.
The fix: always include (forward) declarations of all template specializations. It's best to put those in a single header and include that header from all clients that call your class for any possible template argument.
// my_template.hpp
#include "my_template_fwd.hpp"
#include "my_template_primary.hpp"
#include "my_template_spec_some_type.hpp"
// my_template_fwd.hpp
template<typename> class my_template; // forward declaration of the primary template
// my_template_primary.hpp
#include "my_template_fwd.hpp"
template<typename T> class my_template { /* full definition */ };
// my_template_spec_some_type.hpp
#include "my_template_fwd.hpp"
template<> class my_template<some_type> { /* full definition */ };
// some_client_module.hpp
#include "my_template.hpp" // no ODR possible, compiler will always see unique definition
Obviously, you could reorganize the naming by making subdirectories for template specializations and change the include paths accordingly.

access private member using template trick

From a blog post Access to private members: Safer nastiness by Johannes Schaub - litb:
template<typename Tag, typename Tag::type M>
struct Rob {
friend typename Tag::type get(Tag) {
return M;
}
};
// use
struct A {
A(int a):a(a) { }
private:
int a;
};
// tag used to access A::a
struct A_f {
typedef int A::*type;
friend type get(A_f);
};
template struct Rob<A_f, &A::a>;
int main() {
A a(42);
std::cout << "proof: " << a.*get(A_f()) << std::endl;
}
how get function can be call from a object since its not defined inside class A ?
EDIT:
I don't understand why get must have Tag as parameter instead of a.*get<A_f>()
=> ok it's due to ADL mechanism
You are not calling get from a! Actually what get return is a class pointer to a member inside A and type of it is int A::* so you need an instance of A to access that value.
For example let me play a little with your code:
struct A {
A(int a):a(a) { }
int b;
private:
int a;
};
void test() {
auto p = &A::b;
std::cout << a.*p << std::endl;
}
Did I call p from inside a? a does not have p, this is exactly what happened in your code, get function return &A::a and you use a to read its value! that's all, nothing is wrong and I think it will be compiled in all compilers.
One other question here is: Why C++ allow declaring template using private member of A. C++ standard say:
14.7.2p8 The usual access checking rules do not apply to names used to specify explicit instantiations. [Note: In particular, the template
arguments and names used in the function declarator (including
parameter types, return types and exception specifications) may be
private types or objects which would normally not be accessible and
the template may be a member template or member function which would
not normally be accessible.]
But if you try to instantiate or even typedef specified template then you get an error.
Let's modify your example slightly:
struct A {
private:
int a;
friend void f();
};
// Explicit instantiation - OK, no access checks
template struct Rob<A_f, &A::a>;
// Try to use the type in some way - get an error.
struct Rob<A_f, &A::a> r; // error
typedef struct Rob<A_f, &A::a> R; // error
void g(struct Rob<A_f, &A::a>); // error
// However, it's Ok inside a friend function.
void f() {
Rob<A_f, &A::a> r; // OK
typedef Rob<A_f, &A::a> R; // OK
}
It's legal because friend functions are always in the global scope, even if you implement them inside a class. In other words, this:
class A
{
friend void go() {}
};
is just a shortcut for:
class A
{
friend void go();
};
void go() {}
This is a known compiler bug in gcc and was fixed in a later release.
See-:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41437

Why is it that defining boost::shared_ptr of a templated behaves differently than boost::shared_ptr of a non templated class

I was trying to integrate the boost::share_ptr into a pair of templated classes that were originally derived from a boost::asio example I found. When I define a type within one class which is a shared::ptr of that class. I can't seem to reference the type in another templated class. If I remove templates from the code, it all compiles.
This won't compile:
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace std;
template <typename TSomething1>
class SomeTemplateT : public boost::enable_shared_from_this<SomeTemplateT<TSomething1> >
{
public:
typedef boost::shared_ptr<SomeTemplateT<TSomething1> > Ptr;
static Ptr Create()
{
return Ptr(new SomeTemplateT<TSomething1>());
}
SomeTemplateT()
{
cout << "SomeTemplateT created" << endl;
}
};
template <typename TSomething>
class OtherTemplateT
{
public:
OtherTemplateT()
{
// COMPILATION ERROR HERE
SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
}
private:
};
The code above yields the following compilation error:
src\Templates\main.cpp: In constructor 'OtherTemplateT<TSomething>::OtherTemplateT()':
src\comps\oamp\src\Templates\main.cpp:30: error: expected ';' before 'someTemplate'
Taking virtually the same code without templates compiles without difficulty:
class SomeTemplateT : public boost::enable_shared_from_this<SomeTemplateT>
{
public:
typedef boost::shared_ptr<SomeTemplateT> Ptr;
static Ptr Create()
{
return Ptr(new SomeTemplateT());
}
SomeTemplateT()
{
cout << "SomeTemplateT created" << endl;
}
};
class OtherTemplateT
{
public:
OtherTemplateT()
{
SomeTemplateT::Ptr someTemplate = SomeTemplateT::Create();
}
private:
};
Platform information:
I'm using gcc4.4.0 from MinGW on windows XP (Code:Blocks IDE).
Am I doing something wrong?
EDIT:
I forgot to mention that if I replace the use of the Ptr typedef with the full declaration of the shared ptr:
boost::shared_ptr
Everything compiles fine.
Also, I can use the type in code outside the of the template.
SomeTemplateT<TSomething>::Ptr is a dependent name; that is, its definition depends on the template parameter. The compiler can't assume that it's a type name unless you say so:
typename SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
^^^^^^^^
You need to use typename:
typename SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
This is required to make parsing possible without semantic analysis. Whether SomeTemplateT<TSomething>::Ptr is a type or a member is not known until SomeTemplateT<TSomething> has been compiled.
A example taken from the C++11 Standard (n3290) that demonstrate why the keyword typename (in this context) is useful.
( 14.6 Name resolution [temp.res] )
struct A
{
struct X { };
int X;
};
struct B
{
struct X { };
};
template<class T> void f(T t)
{
typename T::X x;
}
void foo()
{
A a;
B b;
f(b); // OK: T::X refers to B::X
f(a); // error: T::X refers to the data member A::X not the struct A::X
}