Явная специализация шаблона - несколько определений - PullRequest
0 голосов
/ 07 декабря 2018

Я уже делал явные специализации раньше, я просто не могу понять, почему это не работает:

StringUtils.hpp

#ifndef AYC_STRINGUTILS_HPP
#define AYC_STRINGUTILS_HPP

#include <string>

class StringUtils {
public:
    template <typename T>
    static std::string toString(const T& t);
};

#include "StringUtils.tpp"

#endif //AYC_STRINGUTILS_HPP

StringUtils.tpp

#include "StringUtils.hpp"

template<typename T>
std::string StringUtils::toString(const T& t) {
    return std::to_string(t);
}

template<>
std::string StringUtils::toString<std::string>(const std::string& t) {
    return t;
}

Ошибки, которые я получаю, являются ошибками компоновщика с жалобами на множественные определения функции toString.

Многие файлы в проекте используют #include "StringUtils.hpp".

Как я могу попытаться исправить эту ошибку?Что-то не так в классе StringUtils?

Ответы [ 3 ]

0 голосов
/ 07 декабря 2018

В дополнение к решению, предоставленному Брайаном в ответе , вы можете объявить специализацию в файле .hpp / .tpp и определить ее в файле .cpp.

StringUtilsФайл .hpp:

#ifndef AYC_STRINGUTILS_HPP
#define AYC_STRINGUTILS_HPP

#include <string>

class StringUtils {
public:
    template <typename T>
    static std::string toString(const T& t);
};

// Generic implementation.
template<typename T>
std::string StringUtils::toString(const T& t) {
    return std::to_string(t);
}

// Declation of the specialization.
template<>
std::string StringUtils::toString<std::string>(const std::string& t);

#endif //AYC_STRINGUTILS_HPP

Файл StringUtils.cpp:

#include "StringUtils.hpp"

// Definition of the specialization.
template<>
std::string StringUtils::toString<std::string>(const std::string& t) {
    return t;
}

Тестовая программа:

#include <iostream>
#include "StringUtils.hpp"

int main()
{
   std::string a("test");
   std::cout << StringUtils::toString(a) << std::endl;
   std::cout << StringUtils::toString(10) << std::endl;
}

Вывод тестовой программы:

test
10
0 голосов
/ 07 декабря 2018

Специализация шаблонной функции - почти всегда неправильный ответ.

Классы - это плохие пространства имен.

Просто перегрузите вместо специализации.

namespace StringUtils {
  template <typename T>
  std::string toString(const T& t){
    using std::to_string;
    return to_string(t);
  }
  inline std::string toString(std::string s){ return std::move(s); }
}

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

Также обратите внимание, что я включил расширение ADL to_string для пользовательских классов,Просто перегрузите to_steing(X) в пространстве имен X, и StringUtils::toString(X) найдет его.


Ваша непосредственная проблема заключается в том, что вам нужно отметить специализацию inline.

0 голосов
/ 07 декабря 2018

Явная (полная) специализация шаблона функции подчиняется правилу одного определения, поэтому StringUtils::toString<std::string> не должно определяться в нескольких единицах перевода.Вы можете решить эту проблему, объявив ее inline.

...