Какой компилятор правильный в отношении специализации шаблонных методов? - PullRequest
0 голосов
/ 02 августа 2020

Я не разбирался в тонкостях шаблонов, поэтому просто знаю достаточно, чтобы быть опасным. Однако я столкнулся с проблемой (о которой сообщил один из наших тестеров), когда код правильно скомпилировался в Xcode (Clang) и Visual Studio 2019, но поведение было другим, и мне интересно, какой из них был «правильным»

Рассмотрим следующий простой класс:

template <class T>
class foo
{
   void set(int index, T value);
};

Этот шаблонный метод по умолчанию set отлично работал для большинства значений типа T , но мне нужно было специализировать поведение для конкретного типа, назовите его String.

Итак, в связанный файл CPP я добавил следующее:

template <>
void foo<String>::set(int index,  String value)
{
   // code here
};

В Xcode это сработало отлично. Вызов set со вторым параметром String правильно вызвал этот специализированный шаблон.

Однако тот же самый код, скомпилированный с помощью Visual Studio, не прошел, вёл себя по-другому. Тот же самый вызов с параметром String просто вызвал исходный set , а не специализированную версию.

Я предполагаю, что в Xcode компилятор правильно создал вызов с подписью, которая соответствует специализированной версии, которая была доступна в файле CPP и, следовательно, была правильно связана.

Итак, мои вопросы:

  1. Почему это работает в Xcode но не в Visual Studio
  2. Какой компилятор вёл себя правильно и следует ли считать проблему ошибкой в ​​другом компиляторе?

Между прочим, я попытался создать явную подпись в файле заголовка :

template<>
void foo<String>::set(int index, String value );

и Xcode не жаловались на это, и все по-прежнему работало. Однако Visual Studio, хотя и не жаловался на эту подпись заголовка, пожаловалась во время компоновки, что не может найти подходящую реализацию, и поэтому:

Почему это не сработало?

Хотя я нашел способ сделать это, которое сработало для обоих компиляторов (по сути, вставив встроенные версии в файл заголовка, мне бы очень хотелось понять, почему это возникла проблема.

Я заранее благодарю людей.

Edit: bllow - это реальный пример, который я только что собрал. Он компилируется и отлично работает под Xcode (в частности, специализация строк правильно вызывается для переменной g), но не удается связать в Visual Studio 2019 со следующей ошибкой

(publi c: void __cdecl Foo > :: print (int, класс std :: basic_string ) "(? print @? $Foo@V?$basic_string@DU?$char_traits@D@std@@V? $allocator@D@2@@std@@@@QEAAXHV? $basic_string@DU?$char_traits@D@std@@V? $allocator@D@2@@std@@@Z) указано в функции main) указано в функции main)

    Classes.h
    ---------
    #pragma once

    #include <iostream>
    #include <string>

    template <class T>
    class Foo
    {
       public:
          void print(int index, T value)
             {
                std::cout << "Using implicit template\n";
             }
    };




    Classes.cpp
    -----------

    #include "Classes.h"


    template<>
    void Foo<std::string>::print(int i, std::string xyz)
    {
       std::cout << "Using explicit String template\n";
    }



    Main.cpp
    --------

    #include <string>
    #include <iostream>

    #include "Sub/Classes.h"

    //==============================================================================
    int main (int argc, char* argv[])
    {

        Foo<double> f;
        
        f.print(1, 2.0);
        
        Foo<std::string> g;
        
        g.print(1, "abc");

        return 0;
    }
...