Nano Hash - криптовалюты, майнинг, программирование

Clang и Gcc не согласны с явной специализацией после создания экземпляра

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

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

Примечания:

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

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

  • Разница, по-видимому, существует для всех версий ISO после С++ 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
28.05.2019

Ответы:


1

Ни один из компиляторов технически неверен. Код недействителен, но реализации 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;
29.05.2019
  • Вы можете исправить это, объявив явную специализацию сразу после определения singleton в sing.hh. Думаю, это не сработает, потому что Foo еще не было объявлено. Вам нужно будет отправить объявление Foo. Второй подход сработает, и мне кажется, что это самый безопасный подход. +1 за диагностику не требуется. Я пропустил это. 29.05.2019

  • 2

    Из этого ответа здесь и ссылки 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

    28.05.2019
  • Здесь нет предварительного объявления. 29.05.2019
  • @aschepler: struct Foo в явной специализации шаблона. 29.05.2019
  • Новые материалы

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

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..