Clang и Gcc не согласны с явной специализацией после создания - PullRequest
1 голос
/ 29 мая 2019

В каком-то коде, который я рассматриваю, я столкнулся с случаем, когда Clang и Gcc не согласны. Посмотрев вокруг некоторое время, я не могу понять, кто прав.

Отказ от ответственности : я знаю, что есть лучший шаблон синглтона, но это тот, который используется в коде.

Примечания:

  • gcc 7.4.0 в Ubuntu (без ошибок)

  • clang 6.0.0 в Ubuntu (выдает ошибку)

  • Разница, кажется, существует для всех версий ISO после C ++ 11, но я не пробовал ранее.

foo.hh

#include "sing.hh"

class Foo {
    public: 
    Foo();
    ~Foo();
    static Foo *getSingleton(){
        return singleton<Foo>::instance();  
    }
};

foo.cc

include "foo.hh"
//removing this line results in the error for clang disappearing 
template<> singleton<Foo>::GetInstance singleton<Foo>::instance = nullptr; 
int main(){};

sing.hh

template<typename T>
class singleton{
    typedef T *(*GetInstance)(void);
public:

  static GetInstance instance;

};

Результаты:

$ clang++  foo.cc
foo.cc:3:56: error: explicit specialization of 'instance' after instantiation
template<> singleton<Foo>::GetInstance singleton<Foo>::instance = nullptr;
                                                       ^
./foo.hh:10:32: note: implicit instantiation first required here
        return singleton<Foo>::instance();  
                               ^
1 error generated.



$ g++  foo.cc <- No Errors

Ответы [ 2 ]

2 голосов
/ 29 мая 2019

Ни один компилятор технически не прав. Код недействителен, но реализации C ++ не обязаны выдавать диагностическое сообщение об ошибке такого типа.

Стандарт [temp.expl.spec] / 6 говорит (выделено мое):

Если шаблон, шаблон элемента или элемент шаблона класса явно специализированы, то эта специализация должна быть объявлена ​​до первого использования этой специализации, которая вызовет неявную реализацию в каждой единице перевода, в которой такие использование происходит; диагностика не требуется .

Это можно исправить, объявив явную специализацию сразу после определения singleton в sing.hh:

struct Foo;
template<> singleton<Foo>::GetInstance singleton<Foo>::instance;

Или, если вы хотите, чтобы все специализации инициализировались как нулевые указатели, вы можете просто определить элемент шаблона общего класса, опять же, вероятно, в sing.hh. Тогда нет необходимости в явной специализации, если только вам не нужен другой инициализатор для некоторого определенного типа (типов).

template<typename T>
typename singleton<T>::GetInstance singleton<T>::instance = nullptr;
0 голосов
/ 29 мая 2019

Из этого ответа здесь и cpp-ссылка здесь .

Явная специализация может быть объявлена ​​в любой области, где ее основной Шаблон может быть определен [...].

Явная специализация должна появиться после неспециализированной шаблон объявления.

Специализация должна быть объявлена ​​до первого использования, которое может вызвать неявная реализация в каждой единице перевода, где такое использование происходит

Если бы явная специализация была в файле sing.cpp, то ни один компилятор не жаловался бы. В качестве альтернативы вы можете использовать предварительное объявление, чтобы выполнить следующее, и clang, и gcc будут счастливы.

#include <iostream>

template<typename T>
struct singleton
{
    typedef T *(*GetInstance)(void);

    static GetInstance instance;
};

template<>
singleton<struct Foo>::GetInstance singleton<struct Foo>::instance = nullptr;

struct Foo
{
    static Foo *getSingleton()
    {
        return singleton<Foo>::instance();  
    }
};

int main()
{

}

Пример кода онлайн: https://rextester.com/SPZLS83155

...