2

The code:

#include <iostream>
#include <cstddef>
#include <type_traits>

template <class T,T (*g)(),bool (*s)(T),class NP = std::nullptr_t,class dummy = void>  struct pfun;

template <class T,T (*g)(),bool (*s)(T)>
struct pfun<T,g,s,std::nullptr_t,typename std::enable_if<g != nullptr && (std::is_const<T>::value || s == nullptr)>::type>
  {
  pfun() {std::cout << "class pfun<T,g,s,std::nullptr_t,typename std::enable_if<g != nullptr && (std::is_const<T>::value || s == nullptr)>::type>\n";} 
  };

template <class T,T (*g)(),bool (*s)(T),class NP>
struct pfun<T,g,s,NP,typename std::enable_if<g == nullptr && s != nullptr>::type>
  {
  pfun() {std::cout << "class pfun<T,g,s,NP,typename std::enable_if<g == nullptr && s != nullptr>::type>";}
  };
 
template <class T,T (*g)(),bool (*s)(T),class NP>
struct pfun<T,g,s,NP,typename std::enable_if<g != nullptr && s != nullptr>::type>
  {
  pfun() {std::cout << "class pfun<T,g,s,NP,typename std::enable_if<g != nullptr && s != nullptr>::type>";}
  };

template <class T,T (*g)(),bool (*s)(T)>
struct pfun<T,g,s,std::nullptr_t,typename std::enable_if<g == nullptr && s != nullptr>::type> 
  {
  pfun() {std::cout << "class pfun<T,g,s,std::nullptr_t,typename std::enable_if<g == nullptr && s != nullptr>::type>";}
  };

template <class T,T (*g)(),bool (*s)(T)>
struct pfun<T,g,s,std::nullptr_t,typename std::enable_if<g != nullptr && s != nullptr>::type> 
  {
  pfun() {std::cout << "class pfun<T,g,s,std::nullptr_t,typename std::enable_if<g != nullptr && s != nullptr>::type>";}
  };
  
char const gl_r_const_ch('c');
char const gl_fun_r_read_const_ch()  { return gl_r_const_ch; }
pfun<char const,&gl_fun_r_read_const_ch,nullptr> pf_read_const_ch;

int main() { return 0; }

When compiling at the C++14 level gcc-10.2, clang-linux-11.0, VC++-14.2, and VC++-14.2 preview has no problem compiling/linking. But when compiling at the C++17 level, while gcc-10.2 still compiles the code without any problem, clang, VC++, and VC++ preview all give compiling errors.

For clang the result is:

test_pmf.cpp:39:50: error: implicit instantiation of undefined template 'pfun<const char, &gl_fun_r_read_const_ch, nullptr, nullptr_t, void>'
pfun<char const,&gl_fun_r_read_const_ch,nullptr> pf_read_const_ch;
                                                 ^
test_pmf.cpp:5:95: note: template is declared here
template <class T,T (*g)(),bool (*s)(T),class NP = std::nullptr_t,class dummy = void>  struct pfun;

For VC++14.2 an VC++14.2 preview the result is:

test_pmf.cpp
test_pmf.cpp(39): error C2079: 'pf_read_const_ch' uses undefined struct 'pfun<const char,gl_fun_r_read_const_ch,0x0,std::nullptr_t,void>'

The code seems fine to me but maybe someone knows some nuance of C++17 which causes both clang and VC++ to reject the code in C++17, even though gcc accepts it as correct. Does anybody know who is correct here and why the code would not compile in C++17 ?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I have to say that it seems like the shown code is not minimal. Could you simplify the code while maintaining the behavior that you want to show? Also, why have you tagged the question with c++11, when the question is about a difference between 14 and 17? – cigien Mar 22 '21 at 04:21
  • The code can indeed be reduced considerably. I wasn't comfortable editing your question to that extent, so I went ahead and posted a new [question](https://stackoverflow.com/questions/66740897). – cigien Mar 22 '21 at 05:49
  • The code is actually a stripped down version of much more extensive code involved with each partial specialization. You are correct that I could have played around more to see if I could reduce it further and still get the difference between gcc and clang/vc++. But once I stripped down the more extensive code to my example I thought the example should illustrate adequately the situation. – Edward Diener Mar 22 '21 at 07:40
  • Yes, it should have been tagged C++14 and C++17 rather than C++11. Can I change that tag ? – Edward Diener Mar 22 '21 at 07:41
  • Focusing on the specific problem is always preferable when possible; e.g. it's not clear whether your issue stems from invalid specializations, or the `enable_if`, etc. While trying to figure out what the issue is with your code, I ended up with the version that I posted. I think that if I understand what's up with that code, I'll understand the issue with yours. Also, yes you can absolutely edit the tags, so please go ahead and do that. – cigien Mar 22 '21 at 07:47
  • I do not see anything wrong with the partial specialization, or my use of std::enable_if, both of which are perfectly normal AFAICS, so I thought it might be some issue with C++17. But perhaps it is just a clang and vc++ bug. That is why I posted my problem, hoping someone else could shed light on thiis issue. – Edward Diener Mar 22 '21 at 12:52

1 Answers1

0

I simplified the above to:

#include <iostream>
#include <cstddef>
#include <type_traits>

template <class T,T (*g)(),bool (*s)(T),class NP = std::nullptr_t,class dummy = void>  struct pfun;

template <class T,T (*g)(),bool (*s)(T)>
struct pfun<T,g,s,std::nullptr_t,typename std::enable_if<g != nullptr && (std::is_const<T>::value || s == nullptr)>::type>
  {
  pfun() {std::cout << "class pfun<T,g,s,std::nullptr_t,typename std::enable_if<g != nullptr && (std::is_const<T>::value || s == nullptr)>::type>\n";} 
  };
  
char const gl_r_const_ch('c');
char const gl_fun_r_read_const_ch()  { return gl_r_const_ch; }
pfun<char const,&gl_fun_r_read_const_ch,nullptr> pf_read_const_ch;

// char gl_r_ch('c');
// char gl_fun_r_read_ch()  { return gl_r_ch; }
// pfun<char,&gl_fun_r_read_ch,nullptr> pf_read_ch;

int main() { return 0; }

and reported it as a bug to clang and vc++, noting that uncommenting the commented lines and commenting the other three lines does work correctly.