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

#c #templates #unix

#c #шаблоны #unix

Вопрос:

Я пытаюсь перенести некоторый код C из Windows в Solaris (Unix). Необходимо изменить некоторый код шаблона. Я использую компилятор Solaris CC, у g должна возникнуть такая же проблема.

У меня есть определенная часть кода, которая создает некоторые проблемы. Они упрощены следующим образом:

 #include <exception>
#include <cmath>
#include <string>
#include <iostream>

// define the "not implement" error
class tempException: public std::exception
{
public:
    virtual const char* what() const throw()
    {
        return "not been implemented!";
    }
} nondeferr;

// the template class
template <typename T>
class A
{
public:
    template <typename Val>
    Val getValue(T t) { throw nondeferr; }

    template<>
    double getValue(T t) { return exp( 1.5 * t ); } //Specialize the getValue for double type.
};

// test code
int main()
{
    try
    {
        A<int> testA;

        std::cout << testA.getValue<double>(2) << std::endl;
        std::cout << testA.getValue<std::string>(2) << std::endl;
    }
    catch (tempExceptionamp; e)
    {
        std::cout << e.what() << std::endl;
    }

return 0;
}
  

При компиляции этого примера кода в UNIX выдается ошибка компиляции, поскольку явная специализация не может находиться в области видимости класса A.

Здесь функция GetValue отличается только от типа возвращаемого значения, поэтому мы не можем изменить ее, используя способ перегрузки.

И по какой-то причине изменение класса A с простой шаблонной переменной T на класс A с двойными шаблонными переменными T и Val не допускается. Это внесет множество изменений, когда мы попытаемся использовать этот базовый класс.

Могу ли я узнать, есть ли какое-либо решение? В настоящее время я удаляю функцию GetValue, заменяя ее как getDoubleValue… Но это тоже не так хорошо.


Для тех, кому интересно, теперь класс A выглядит следующим образом:

 template <typename T>
class A
{
public:
    // the Get Value we want
    template <typename R>
    R getValue(T t) { return get_value_impl<R>::apply(*this, t); }

    // the general get value struct
    template<typename R, typename = void>
    struct get_value_impl
    {
        static R apply(A a, T t) { throw nondeferr; }
    };

    // partial specialization, which is allowed in std C  
    template <typename S>
    struct get_value_impl<double, S>
    {
        static double apply(A a, T t) { return exp( 1.5 * t ); }
    };
};
  

Логика, лежащая в основе, заключается в том, что явная специализация не допускается стандартом. Однако частичная специализация допускается. Еще раз спасибо Anycorn за великолепное решение.

Ответ №1:

 // the template class
template <typename T>
class A {
    template<>
    double getValue(T t) { return exp( 1.5 * t ); }
};
  

Это не разрешено стандартом.

делать:

 template <typename T>
class A {
    template<class R>
    R getValue(T t) { return get_value_impl<double>::apply(*this, t); }
    template<class R, class = void>
    struct get_value_impl; // specialize this
};
  

Комментарии:

1. Спасибо за решение, я применяю то, что вы предложили, к моему тестовому коду. Это работает нормально …. 🙂

Ответ №2:

Не разрешается специализировать функцию-член без специализации окружающего класса. Visual Studio допускает это в качестве расширения.