Clang and gcc differently when handling constexpr template and static member generation?

Consider the following program (sorry for the length, this is the shortest way to express the problem):

#include <iostream>
#include <vector>
#include <typeindex>

using namespace std;

std::vector<std::type_index>&
test_vector()
{
  static std::vector<std::type_index> rv;
  return rv;
}

template <typename T>
class RegistrarWrapper;

template<typename T>
class Registrar
{
  Registrar()
  {
    auto& test_vect = test_vector();
    test_vect.push_back(std::type_index(typeid(T)));
  }
  friend class RegistrarWrapper<T>;
};

template <typename T>
class RegistrarWrapper
{
  public:
    static Registrar<T> registrar;
    typedef Registrar<T> registrar_t;
};

template <typename T>
Registrar<T> RegistrarWrapper<T>::registrar;


template <typename T>
class Foo
{
  public:
    // Refer to the static registrar somewhere to make the compiler
    // generate it ?!?!?!?
    static constexpr typename RegistrarWrapper<Foo<T>>::registrar_t& __reg_ptr =
      RegistrarWrapper<Foo<T>>::registrar;
};


int main(int argc, char** argv)
{
  Foo<int> a;
  Foo<bool> b;
  Foo<std::string> c;

  for(auto&& data : test_vector()) {
    std::cout << data.name() << std::endl;
  }

}

When compiling with clang++(version 3.5.2, of course, c -std=c++11), this program outputs (for reading it is read through c++filt):

Foo<int>
Foo<bool>
Foo<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >

But with g++(verified versions 4.8.5, 4.9.3 and 5.2.0) it does not output anything! What's going on here? Which compiler complies with the C ++ standard? How can I create this effect in the agnostic way of the compiler (preferably without any utilities)?

+4
source share
1 answer

-, . registrar , . , , .

, Foo a, b c main:

template<typename T> class Foo
{
public:
   Foo() { (void)&RegistrarWrapper<Foo<T>>::registrar; }
};

, . , , :

template<class T> constexpr std::size_t register_class() 
{ 
   (void)&RegistrarWrapper<T>::registrar; 
   return 1; 
}

template<typename T> class Foo
{
   static char reg[register_class<Foo<T>>()];
};

- (. ).

Clang 3.7.0, GCC 5.2.0 Visual ++ 2015, . constexpr, ++ 14. , ++ 11, .


, , , __reg_ptr , -. N4527:

14.7.1p2:

[...] ( ) , , .

constexpr, ( ) , odr ( registrar), .

14.7.1p1:

[...] , , - , -, , [...]

, . , .

, constexpr. CWG 1581, , , , , constexpr . ( ...), .


: Foo , :

template class Foo<int>;
template class Foo<bool>;
template class Foo<std::string>;

int main()
{
   for(auto&& data : test_vector()) {
      std::cout << data.name() << std::endl;
   }
}

14.7.2p8:

, ( ) [...]

, , , , , GCC __reg_ptr. ([14.7p5.1]), . , .

+1

Source: https://habr.com/ru/post/1614317/


All Articles