On 22 June 2017 at 17:42, Edward Diener <eldlistmailingz@xxxxxxxxxxxxxx> 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;