Применение шаблона SFINAE с универсальной ссылкой - PullRequest
0 голосов
/ 17 ноября 2018

У меня есть следующий код:

#include <utility>
#include <iostream>
#include <queue>
#include <functional>
#include <stdio.h>
#include <future>

class Runner {
public:
    virtual void run() = 0;
    virtual ~Runner() {
    }
};

class Command: public Runner {
public:
    Command() {
        std::cout << "constructor" << std::endl;
    }
    virtual void run() {
    }
};

#define EXTEND(T, F) , typename = typename std::enable_if<std::is_base_of<F, typename std::decay<T>::type>::value, typename std::decay<T>::type>::type
#define NOT_EXTEND(T, F) , typename = typename std::enable_if<!std::is_base_of<F, typename std::decay<T>::type>::value, typename std::decay<T>::type>::type

class Executor {
private:
    std::queue<std::function<void(void)> > q;
public:
    template<class T EXTEND(T, Runner)>
    void push(T&& toBepushed) {
        q.push(
                std::bind(&std::decay<T>::type::run,
                        std::forward<T>(toBepushed)));
    }
    template<typename T NOT_EXTEND(T, Runner)>
    void push(T&& toBepushed) {
        q.push(std::forward<T>(toBepushed));
    }
    void perform() {
        std::function<void(void)>&& f = std::move(q.front());
        f();
    }
};

int main() {
    Executor b;
    Command c;
    b.push(c);
    b.perform();
    return 0;
}

При компиляции у меня появляется следующая ошибка:

g ++ -std = c ++ 0x -O2-g3 -Wall -c -fmessage-length = 0 -MMD -MP -MF "main.d" -MT "main.o" -o "main.o" "../main.cpp" ../main.cpp: 45: 7: ошибка: шаблон void Bar :: push (T &&) «не может быть перегруженBar :: push (T &&) 'void push (T && toBepush) {^ ~~~ make: *** [subdir.mk:20: main.o] Ошибка 1

Я пытаюсьприменять SFINAE для применения метода push в соответствии с используемым типом.Как решить?

1 Ответ

0 голосов
/ 17 ноября 2018

Аргумент по умолчанию не является частью списка параметров шаблона, поэтому ваши два push имеют одинаковый список параметров шаблона, что приводит к повторному объявлению.

Это типичный недостаток подхода typename = std::enable_if_t<...>. Вместо этого вы должны использовать std::enable_if_t<..., int> = 0 подход.

Изменить на это:

#define EXTEND(T, F) , typename std::enable_if<std::is_base_of<F, typename std::decay<T>::type>::value, int>::type = 0
#define NOT_EXTEND(T, F) , typename std::enable_if<!std::is_base_of<F, typename std::decay<T>::type>::value, int>::type = 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...