PacktPublishing / Template-Metaprogramming-with-CPP

Template Metaprogramming with C++, published by Packt
MIT License
77 stars 24 forks source link

Chapter 2 - Example not working with Clang / GCC #4

Open ludvikjerabek opened 8 months ago

ludvikjerabek commented 8 months ago

Issue with Ubuntu 22.04, CMAKE 3.22.1, g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0. I validated that the example works against VC++.

GCC Output:

In file included from /mnt/c/Users/username/Documents/GitHub/Template-Metaprogramming-with-CPP/src/chapter_02/source2.cpp:1:
/mnt/c/Users/username/Documents/GitHub/Template-Metaprogramming-with-CPP/src/chapter_02/wrapper.h:10:32: error: expected unqualified-id before ‘;’ token
   10 |    extern template wrapper<int>;

Clang Output:

In file included from /mnt/c/Users/ljerabek/Documents/GitHub/Template-Metaprogramming-with-CPP/src/chapter_02/source1.cpp:1:
/mnt/c/Users/ljerabek/Documents/GitHub/Template-Metaprogramming-with-CPP/src/chapter_02/wrapper.h:10:20: error: declaration does not declare anything
   extern template wrapper<int>;
namespace ext
{
   template <typename T> struct wrapper
   {
      T data;
   }; 

   extern template wrapper<int>; // This is the line causing the problem. 

   void f();
   void g();
}
ludvikjerabek commented 8 months ago

For Chapter 2 you must make the following changes:

Add the following to src\chapter_02\main.cpp

#include <memory> // Needed for std::make_unique
#include <cstring> // Needed for std::strcpy

Change the following in src\chapter_02\wrapper.h

- extern template wrapper<int>;
+ extern template struct wrapper<int>;

Change the following in src\chapter_02\source1.cpp

- template wrapper<int>;
+ template struct wrapper<int>;

Change the following in src\chapter_02\main.cpp

- template wrapper<int>; 
+ template struct wrapper<int>;

To fix the following error you should modify CMakeList.txt to be permissive.

if(MSVC)
  message(status "Setting MSVC flags")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHc /Zc:__cplusplus /std:c++latest")
  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else()
  message(status "Setting GCC/Clang flags")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a -fexceptions -g -Wall -fpermissive") 
endif()

Otherwise you will get the following:

/mnt/c/Users/ljerabek/Documents/GitHub/Template-Metaprogramming-with-CPP/src/chapter_02/main.cpp: At global scope:
/mnt/c/Users/ljerabek/Documents/GitHub/Template-Metaprogramming-with-CPP/src/chapter_02/main.cpp:524:32: error: duplicate explicit instantiation of ‘T n226::add(T, T) [with T = int]’ [-fpermissive]
  524 | template int n226::add(int, int);       // [2]

It seems the issue has to do with redefining add:

template struct n226::wrapper<double>;  // [2]
namespace n226
{
   template <typename T>
   T add(T const a, T const b)
   {
      return a + b;
   }
    template int add(int, int);         // [1] <-- This appears to conflict with 
}
template int n226::add(int, int);       // [2] <-- This definition. 

Since namespace n226 is never used you can just comment it out or delete it instead of adding the -fpermissive.

ludvikjerabek commented 8 months ago

It appears the examples were only tested on MSVC++ and it would be good if someone from the team would validated against other compilers. Can someone from the Packt team address these issues?

ludvikjerabek commented 8 months ago

Tested g++-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0 still fails unless you make changes. Going to try GCC 13 next to see if it makes a difference.

ludvikjerabek commented 8 months ago

Just finished testing with g++-13 (Ubuntu 13.1.0-8ubuntu1~22.04) 13.1.0 the code sample still fail.