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

Jonathan Wakely jwakely.gcc@gmail.com
Fri Jun 23 14:46:00 GMT 2017


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.

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;



More information about the Gcc-help mailing list