Компилятор MSVC создает определение шаблона функции по умолчанию, хотя специализация существует - PullRequest
0 голосов
/ 15 января 2019

Следующий код компилируется и работает правильно в macOS, используя Clang, но не в Windows, используя MSVC 2017.

// File: toString.h
#include <string>
template<typename T>
const std::string toString(T){return "";}

// File: toString.cpp
#include "toString.h"
template <>
const std::string toString<int>(int value){
    return std::to_string(value);
}

// File: main.cpp
#include <iostream>
#include "toString.h"

int main() {
    // specialized
    std::cout <<"int: "<< toString(1) << std::endl;
    // not specialized
    std::cout <<"double: "<< toString(1.0) << std::endl;
    return 0;
}

// Expected output:
// int: 1
// double: 

В компоновщике происходит сбой, поскольку функция создается неявно, а не связана со специализацией int, что приводит к дублированию символов.

Если реализация шаблона по умолчанию удалена, то строка, печатающая double, потерпит неудачу, так как не будет символа, связывающего его с *. 1007 *

Мой вопрос заключается в том, существует ли какой-либо способ достижения того же результата в Windows с MSVC, если у main.cpp нет какой-либо видимости специализации toString (объявление или определение).

Если нет, охватывается ли это стандартом или просто подробностями реализации компилятора?

1 Ответ

0 голосов
/ 15 января 2019

В tostring.h нет ничего, что сообщало бы компилятору о том, что ваша специализация существует. Поэтому при компиляции main.cpp компилятор просто создает экземпляр шаблона, объявленный в заголовке. Нарушение правила одного определения, поэтому поведение не определено. То, что это работает так, как вы ожидаете в clang, в основном связано с удачей в том, что из двух доступных определений во время соединения clang выбрал то, что вы хотели.

Чтобы исправить это, вам нужно заранее объявить вашу специализацию в заголовке, чтобы компилятор знал, не создавать экземпляр шаблона при компиляции main.cpp:

//toString.h
#include <string>
template<typename T>
const std::string toString( T ) { return ""; }

template <>
const std::string toString<int>( int value );
...