2009-04-20 5 views
8

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

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

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(); 
    } 
} 

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

ответ

12

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

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' 
} 

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

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' 
} 
+0

hm Я попробовал то же самое сейчас, но поместил его в файл .hpp и попытался включить его ... тогда я получаю ошибку «множественное определение vodi X: ff (тест ). Я не вижу, что будет Разница? – Rolle

+1

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

+0

Почему я должен добавить встроенный для первого случая? Если нет, я получаю ошибку компиляции. – sop

3

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

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

template <> 
void A::foo<void>() 
{ 
} 
+0

Спасибо за ответ. Для меня это не имеет значения, если они находятся внутри класса или нет; но я не могу заставить его работать в любом случае. Является ли мой синтаксис неправильным или что-то в коде, который я поставил? – Rolle

+0

Дело в том, что вы явно специализируете функцию в пространстве имен с квалифицированным объявлением функции. C++ не позволяет повторно добавить ключевое слово 'static', чтобы вы просто удалили его. В моем примере выше показано, как явно специализировать статический член. –

2

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

+0

извините, попробовал это, но не работает. Вы скомпилировали под gcc? Я думаю, что это работает под VS, например ... – Rolle

+0

Это версия g ++ 3.4.5 – 2009-04-20 10:08:04

+0

Это ее статика - удалите их, и все должно быть плавным, оно компилируется с помощью goau, я обновлю ответ – 2009-04-20 10:11:09

4

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

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

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

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

+1

да очень хорошая точка – 2009-04-20 09:50:31

+0

I я уверен, что не будет работать. Т не определяется нигде? – Rolle

+0

@ Rolle Извините "шаблон " не сохранился, чтобы скопировать/вставить. – Rexxar

1

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

Смежные вопросы