Bug in c++11 mode when instantiating template with local class

Edward Diener eldlistmailingz@tropicsoft.com
Fri Jun 23 17:43:00 GMT 2017


On 6/23/2017 10:46 AM, Jonathan Wakely wrote:
> On 22 June 2017 at 17:42, Edward Diener <eldlistmailingz@tropicsoft.com> wrote:
>> The code below asserts when being compiled with gcc in c++11 mode:
>>
>> ----------------------------------------------------------------------
>>
>> #include <cassert>
>>
>> typedef char yes_type;
>> struct no_type
>> {
>>     char padding[8];
>> };
>>
>> template
>>      <
>>      class enclosing_type,
>>      class static_type
>>      >
>> struct has_static_member_function_StaticFunction
>>      {
>>      template<static_type *> struct helper;
>>      template<class internal_enclosing_type> static yes_type
>> chkt(helper<&internal_enclosing_type::StaticFunction> *);
>>      template<class internal_enclosing_type> static no_type chkt(...);
>>      static const bool
>> value=(sizeof(chkt<enclosing_type>(0))==sizeof(yes_type));
>>      };
>>
>>
>>      class AClass
>>      {
>>      public:
>>          static void StaticFunction()
>>          {
>>          }
>>      };
>>
>> int main()
>> {
>>      class ANestedClass
>>      {
>>      public:
>>          static void StaticFunction()
>>          {
>>          }
>>      };
>>
>>      assert((has_static_member_function_StaticFunction<ANestedClass,void
>> ()>::value));
>>
>>      return 0;
>> }
>>
>> -------------------------------------------------------------------------
>>
>> If the 'assert" line instead is:
>>
>> assert((has_static_member_function_StaticFunction<AClass,void ()>::value));
>>
>> the assert does not occur. In other words the class template's 'value' is
>> false when passing the local class and true when passing the non-local
>> class.
>>
>> The code is a simplified version of my Boost tti's library code for checking
>> if a static member function of a given name exists within a class.
>>
>> Is this a gcc bug or is my code wrong for local classes in c++11 mode, as
>> opposed to non-local classes ?
>>
>> I am fully aware that instantiating a template with a local class type is
>> forbidden prior to c++11.
>>
>> The compile and link lines, for gcc 7.1 as an example, are:
>>
>> somepath/g++ -ftemplate-depth-128 -Wno-unused-local-typedefs
>> -ftrack-macro-expansion=0 -Wno-unused-variable -std=c++11 -O0 -fno-inline
>> -Wall -pedantic -g -march=i686 -m32 -c -o somepath/example.o example.cpp
>>
>> somepath/g++ -o example.exe -Wl,--start-group somepath/example.o
>> -Wl,-Bstatic  -Wl,-Bdynamic  -Wl,--end-group -g -march=i686 -m32
>>
>> If this is a bug in gcc I will be happy to report it on the bug tracker if
>> it has not already been reported.
>>
>>
>>
>>
> 
> I don't think it's a bug. The code can be simplified considerably:
> 
> template<void(*)()> struct helper { };
> 
> struct AClass
> {
>    static void StaticFunction() { }
> };
> 
> int main()
> {
>    struct ANestedClass
>    {
>      static void StaticFunction() { }
>    };
> 
>    helper<&AClass::StaticFunction> ok;
>    helper<&ANestedClass::StaticFunction> error;
> }
> 
> GCC, Clang and EDG all reject this for the same reason: you're using
> the address of a function with no linkage for a non-type template
> argument.
> 
> [basic.link] says that although ANestedClass has internal linkage, the
> static member function has no linkage.

Could you point out where in [basic.link] this is specified ? I admit I 
have a great deal of trouble understanding the rules for internal, 
external, and no linkage of names in section 3.5 of the C++ standard. 
But I do find it odd that if a local class name has internal linkage, a 
static member function name of that local class has no linkage.

> 
> N.B. https://wg21.link/n2187 allowed types with internal linkage to be
> used for template arguments, and https://wg21.link/cwg1155 allowed the
> addresses of objects with internal linkage to be used for non-type
> template arguments, but internal linkage is not the same as no
> linkage.
> 
> I believe the reason the code is invalid is because otherwise you
> could declare an object with external linkage using a type with no
> linkage:
> 
> static helper<&ANestedClass::StaticFunction> foo;

In your example doesn't 'foo' have internal linkage because it is 
declared 'static' ?



More information about the Gcc-help mailing list