{"id":466,"date":"2009-12-20T01:01:33","date_gmt":"2009-12-20T01:01:33","guid":{"rendered":"http:\/\/kera.name\/articles\/?p=466"},"modified":"2011-06-22T09:29:07","modified_gmt":"2011-06-22T09:29:07","slug":"c-lookup-and-template-oddities","status":"publish","type":"post","link":"https:\/\/kera.name\/articles\/2009\/12\/c-lookup-and-template-oddities\/","title":{"rendered":"C++ Lookup And Template Oddities"},"content":{"rendered":"<p><b>Non-type Lookup<\/b><\/p>\n<p>During a discussion about the validity of <code>A::A<\/code> (and the fact that you cannot pass explicit template parameters to a template constructor) it came up that although non-types are ignored in the lookup for a base-clause, the same is not true for typedef&#8230; even though clearly only types are to be expected in either case.<\/p>\n<p>Observe:<\/p>\n<p><textarea name=\"code\" class=\"cpp:nocontrols:nogutter\" cols=\"60\" rows=\"10\">struct A {};\nvoid A();<\/p>\n<p>typedef A lulz;<\/p>\n<p>\/\/ this is illformed; void A() is assumed in the typedef.\n\/\/ error: 'A' does not name a type<\/textarea>\n<\/p>\n<p>But:<\/p>\n<p><textarea name=\"code\" class=\"cpp:nocontrols:nogutter\" cols=\"60\" rows=\"10\">struct A {};\nvoid A();<\/p>\n<p>struct B : A {};<\/p>\n<p>\/\/ valid; non-types are ignored during lookup<\/textarea>\n<\/p>\n<p>Stupid language.<\/p>\n<p><b>Constructor template parameters<\/b><\/p>\n<p>This discussion had come about from a debate over the technique displayed in the following example (&#034;BARK&#034; is a <a href=\"http:\/\/www.xs4all.nl\/~weegen\/eelis\/geordi\/\">third-party<\/a> preprocessor macro that outputs the signature of the function that it&#039;s in):<\/p>\n<p><textarea name=\"code\" class=\"cpp:nocontrols:nogutter\" cols=\"60\" rows=\"10\">struct A {\ntemplate <typename T>\nA(const T& x) {\nBARK;\n}\n};<\/p>\n<p>int main() {\nA a(3);\n}<\/p>\n<p>\/\/ output: A(const int&)<\/textarea>\n<\/p>\n<p>Using the template constructor in this way is valid because the template parameter is deduced to be int from the function argument 3.<\/p>\n<p>Now, let&#039;s look at the case where the class itself is the template. The class&#039;s template parameters cannot be deduced from arguments to its constructor, alas (at least not until C++0x):<\/p>\n<p><textarea name=\"code\" class=\"cpp:nocontrols:nogutter\" cols=\"60\" rows=\"10\">template <typename T>\nstruct A {\nA(const T& x) {\nBARK;\n}\n};<\/p>\n<p>int main() {\nA a(3);\n}<\/p>\n<p>\/\/ error: invalid use of template-name 'A' without an\n\/\/ argument list<\/textarea>\n<\/p>\n<p>However you can, of course, specify the template class parameter explicitly:<\/p>\n<p><textarea name=\"code\" class=\"cpp:nocontrols:nogutter\" cols=\"60\" rows=\"10\">template <typename T>\nstruct A {\nA(const T& x) {\nBARK;\n}\n};<\/p>\n<p>int main() {\nA<int> a(3);\n}<\/p>\n<p>\/\/ output: A(const int&) A(const int&)<\/textarea>\n<\/p>\n<p>You&#039;d expect that specifying a template parameter explicitly is always valid, and that only when trying to rely on implicit deduction might things get a bit hairy.<\/p>\n<p>But you actually can&#039;t specify a template constructor parameter explicitly at all. The interesting thing here is in GCC&#039;s diagnostic, which isn&#039;t quite what you might expect:<\/p>\n<p><textarea name=\"code\" class=\"cpp:nocontrols:nogutter\" cols=\"60\" rows=\"10\">struct A {\ntemplate<typename T>\nA(const T& x) {\nBARK;\n}\n};<\/p>\n<p>int main() {\nA::A<int>(3);\n}<\/p>\n<p>\/\/ GCC error: A is not a template type<\/textarea>\n<\/p>\n<p>What is happening here is that any class <code>A<\/code> is brought into its own scope. So as a type, <code>A::A<\/code> is equivalent to <code>A<\/code>, as is <code>A::A::A<\/code> and <code>A::A::A::A::A::A::A<\/code>. GCC parses <code>A::A&lt;int&gt;()<\/code> as <code>A&amp;lt;int&amp;gt;()<\/code>, then attempts to construct a temporary of type <code>A&amp;lt;int&amp;gt;<\/code>, but class <code>A<\/code> isn&#039;t itself a template so this fails.<\/p>\n<p>A lengthy debate ensued and it was concluded that GCC is erroneous here. Comeau in fact agrees with our ultimate interpretation of the standard, and allows this by correctly parsing <code>A::A&lt;int&gt;<\/code> as the constructor <code>A&amp;lt;int&amp;gt;<\/code> of class <code>A<\/code>&#8230; although it&#039;s still not possible to directly invoke the constructor.<\/p>\n<p><textarea name=\"code\" class=\"cpp:nocontrols:nogutter\" cols=\"60\" rows=\"10\">\/\/ Comeau error: a constructor or destructor may not have its address taken<\/textarea>\n<\/p>\n<p>I&#039;m actually still not 100% clear on this, so please jump on the wagon in the post comments if you can shed some more light on the issue.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I explore a few oddities with templates and types in C++.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[21,20],"_links":{"self":[{"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/posts\/466"}],"collection":[{"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/comments?post=466"}],"version-history":[{"count":8,"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/posts\/466\/revisions"}],"predecessor-version":[{"id":725,"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/posts\/466\/revisions\/725"}],"wp:attachment":[{"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/media?parent=466"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/categories?post=466"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kera.name\/articles\/wp-json\/wp\/v2\/tags?post=466"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}