специализация шаблона для статических функций-членов; как? - PullRequest
9 голосов
/ 20 апреля 2009

Я пытаюсь реализовать функцию шаблона с ручками void по-разному, используя специализацию шаблона.

Следующий код дает мне «Явную специализацию в области отсутствия пространства имен» в gcc:

template <typename T>
static T safeGuiCall(boost::function<T ()> _f)
{
    if (_f.empty())
        throw GuiException("Function pointer empty");
    {
        ThreadGuard g;
        T ret = _f();
        return ret;
    }
}

// template specialization for functions wit no return value
template <>
static void safeGuiCall<void>(boost::function<void ()> _f)
{
    if (_f.empty())
        throw GuiException("Function pointer empty");
    {
        ThreadGuard g;
        _f();
    }
}

Я попытался переместить его из класса (класс не является шаблоном) в пространство имен, но затем я получаю сообщение об ошибке "Явная специализация не может иметь класс хранения" Я читал много дискуссий по этому поводу, но люди, похоже, не согласны с тем, как специализировать шаблоны функций. Есть идеи?

Ответы [ 5 ]

15 голосов
/ 20 апреля 2009

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

template <typename X> struct Test {}; // to simulate type dependency

struct X // class declaration: only generic
{
   template <typename T>
   static void f( Test<T> );
};

// template definition:
template <typename T>
void X::f( Test<T> ) {
   std::cout << "generic" << std::endl;
}
template <>
inline void X::f<void>( Test<void> ) {
   std::cout << "specific" << std::endl;
}

int main()
{
   Test<int> ti;
   Test<void> tv;
   X::f( ti ); // prints 'generic'
   X::f( tv ); // prints 'specific'
}

Когда вы выводите его за пределы класса, вы должны удалить ключевое слово static. Статическое ключевое слово вне класса имеет особое значение, отличное от того, что вы, вероятно, хотите.

template <typename X> struct Test {}; // to simulate type dependency

template <typename T>
void f( Test<T> ) {
   std::cout << "generic" << std::endl;
}
template <>
void f<void>( Test<void> ) {
   std::cout << "specific" << std::endl;
}

int main()
{
   Test<int> ti;
   Test<void> tv;
   f( ti ); // prints 'generic'
   f( tv ); // prints 'specific'
}
4 голосов
/ 20 апреля 2009

Это не прямой ответ на ваш вопрос, но вы можете написать это

template <typename T>
static T safeGuiCall(boost::function<T ()> _f)
{
        if (_f.empty())
                throw GuiException("Function pointer empty");
        {
                ThreadGuard g;
                return _f();
        }
}

Должно работать, даже если _f () вернет 'void'

Edit: в более общем случае, я думаю, мы должны предпочесть перегрузку функций вместо специализации. Вот хорошее объяснение этому: http://www.gotw.ca/publications/mill17.htm

3 голосов
/ 20 апреля 2009

Вы можете объявить явную специализацию так же, как вы бы определили функцию-член вне ее класса:

class A
{
public:
  template <typename T>
  static void foo () {}
};

template <>
void A::foo<void> ()
{
}
2 голосов
/ 20 апреля 2009

Похоже, ваша проблема связана с boost :: function - работают следующие специализации:

template <typename T>
T safeGuiCall()
{
    return T();
}

template <>
void safeGuiCall<void>()
{
}

int main() {
    int x = safeGuiCall<int>();     // ok
    //int z = safeGuiCall<void>();  // this should & does fail
    safeGuiCall<void>();            // ok
}
1 голос
/ 30 ноября 2010

У меня была похожая проблема. Если вы посмотрите на исходный пост, я оставил первый статический вход, но вынул второй, и ОБА ошибки исчезли.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...