Non-type parameter with no linkage

132 views
Skip to first unread message

Edward Diener

unread,
Jun 25, 2017, 10:28:59 PM6/25/17
to ISO C++ Standard - Discussion
According to the C++ standard a template-argument for a non-type, non-template template-parameter which is a constant expression must have internal or external linkage, therefore excluding such a constant expression which has no linkage. Why is this separation made for such a template-argument ?

I see nothing practically wrong with


template<void(*)()> struct helper { };

struct AClass
{
   
static void StaticFunction() { }
};

int main()
{
   
struct ANestedClass
   
{
     
static void StaticFunction() { }
   
};

   helper
<&AClass::StaticFunction> ok;
   helper
<&ANestedClass::StaticFunction> error;
}

the statement

helper<&ANestedClass::StaticFunction> error;

but it is illegal beccause AClass::StaticFunction has no linkage, while the statement

helper<&AClass::StaticFunction> ok;

is perfectly legal because AClass::StaticFunction has external or internal linkage.

Edward Diener

unread,
Jun 27, 2017, 9:19:56 AM6/27/17
to ISO C++ Standard - Discussion


On Sunday, June 25, 2017 at 10:28:59 PM UTC-4, Edward Diener wrote:
According to the C++ standard a template-argument for a non-type, non-template template-parameter which is a constant expression must have internal or external linkage, therefore excluding such a constant expression which has no linkage. Why is this separation made for such a template-argument ?

I see nothing practically wrong with


template<void(*)()> struct helper { };

struct AClass
{
   
static void StaticFunction() { }
};

int main()
{
   
struct ANestedClass
   
{
     
static void StaticFunction() { }
   
};

   helper
<&AClass::StaticFunction> ok;
   helper
<&ANestedClass::StaticFunction> error;
}

the statement

helper<&ANestedClass::StaticFunction> error;

but it is illegal beccause AClass::StaticFunction has no linkage, while the statement

I mis-typed and this should be written as:

"but it is illegal because ANestedClass::StaticFunction has no linkage, while the statement"
 

Paul "TBBle" Hampson

unread,
Jul 18, 2017, 7:54:17 AM7/18/17
to ISO C++ Standard - Discussion
On Monday, 26 June 2017 12:28:59 UTC+10, Edward Diener wrote:
According to the C++ standard a template-argument for a non-type, non-template template-parameter which is a constant expression must have internal or external linkage, therefore excluding such a constant expression which has no linkage. Why is this separation made for such a template-argument ?


I believe this was changed by N4268 for C++17. Comparing C++14 and C++17, the relevant text ([temp.arg.nontype]/1 in C++14, now /2) has been changed from a list of allowed things, to a list of disallowed things. In effect, the address of any static member function is now valid, irrespective of linkage, as all static member functions are converted constant expressions.

Clang 4 in c++1z mode is happy with your posted code-sample, but rejects it in c++14 mode. All versions of gcc I tried rejects it in both, yet claims to have implemented N4268 in gcc 6. MSVC 19 is also happy with the code snippet.



So possibly this change doesn't mean what I think it means, or it doesn't mean what whoever applied N4268 thinks it means...

Interestingly, you can see that MSVC has named the function with no linkage anonymously, and given it a COMDAT section. I wonder if main had been static, whether another translation unit with the same code would have produced an identically-named COMDAT section and hence be treated as the same object...

Paul "TBBle" Hampson

unread,
Jul 18, 2017, 8:13:19 AM7/18/17
to ISO C++ Standard - Discussion


On Tuesday, 18 July 2017 21:54:17 UTC+10, Paul "TBBle" Hampson wrote:
On Monday, 26 June 2017 12:28:59 UTC+10, Edward Diener wrote:
According to the C++ standard a template-argument for a non-type, non-template template-parameter which is a constant expression must have internal or external linkage, therefore excluding such a constant expression which has no linkage. Why is this separation made for such a template-argument ?


I believe this was changed by N4268 for C++17. Comparing C++14 and C++17, the relevant text ([temp.arg.nontype]/1 in C++14, now /2) has been changed from a list of allowed things, to a list of disallowed things. In effect, the address of any static member function is now valid, irrespective of linkage, as all static member functions are converted constant expressions.


https://stackoverflow.com/q/43213997/166389 documents the same bug in gcc, also affecting captureless lambda converted to a function pointer.

Edward Diener

unread,
Jul 28, 2017, 1:54:04 AM7/28/17
to ISO C++ Standard - Discussion
Thank you for your explanation of this issue. I too can see that it works correctly in clang 4.0 in c++1z mode, but does not work correctly in gcc-7.1 in c++1z mode. Also that for VC++ 14.0/14.1 it works correctly in VC++ /std:latest mode but erroneously also works for VC++ 14.0/14,1 in std:c++14 mode.
Reply all
Reply to author
Forward
0 new messages