1

Скажет, у меня есть шаблон:Pass Функции Метод Prototype

template <typename T> 
class foo{ 
    void (T::bar*)(int); 
public: 
    void setMethod(void (T::*)(int) f) 
}; 

Есть ли способ, чтобы использовать функцию, не являющийся членом с этим шаблоном?

Я пробовал:

  • foo<void>().setMethod(&func);
  • foo<nullptr_t>().setMethod(&func);
+4

Нет, нет. Чего вы хотите достичь, поэтому я могу предложить обходные пути? – Wintermute

+0

Если вы хотите использовать иногда функции-члены, а иногда и обычные функции, вы должны искать '' 'function' и' bind' – Christophe

+0

@Wintermute Я хотел бы иметь возможность создавать 'multi_map' с ключом тип объекта и значения - это функции, которые я добавил к карте для этого типа. Моя надежда состояла в том, чтобы использовать 'foo' как тип значения для' multi_map'. Но это слишком важно для решения одного вопроса. –

ответ

1

Нет, это не возможно.

Точный характер полезного обходного пути зависит от характера проблемы, но скорее всего он будет включать std::function и std::bind (или лямбда). В общих чертах фокус обычно заключается в том, чтобы переписать foo таким образом, что ему не нужно заботиться о той функции, которая привязана к ней (что и есть для std::function).

Один из способов это может быть сделано

template <typename T> 
class foo{ 
public: 
    // Here we do not care about the type of function we're binding 
    template<typename Func> 
    void setMethod(Func f) { func_ = f; } 

    void callMethod(T &obj) { func_(obj); } 

private: 
    // only about its signature 
    std::function<void(T&)> func_; 
}; 

Учитывая тип

struct A { 
    void foo(); 
    void bar(int); 
}; 

и функция

void qux(A &); 

Это позже можно сделать любой из

Foo<A> f; 

f.setMethod(&A::foo); 
f.setMethod(qux); 
f.setMethod(std::bind(&A::bar, std::placeholders::_1, 2)); 
f.setMethod([](A &obj) { obj.foo(); }); 

Или позвонить по телефону setMethod со всем, что имеет operator(), принимающее A&.

В случае, если требуется замена Liskov (что относится к OP), это не сработает, потому что foo не может предложить интерфейс в зависимости от аргументов шаблона в общем базовом классе. Тогда два варианта остаются:

  • Если объект функция должна быть вызван могут быть связаны в то же время, как функции, можно сделать foo класс, у него хранить std::function<void()> и засунуть std::bind(&SomeClass::memberfunction, SomeObject) внутрь.
  • В противном случае лучшее, что вы собираетесь получить без злого хакера, ограничивает общий базовый класс тем, что было бы T аргументами foo.

Если ваши потребности превышают это, вы пытаетесь растянуть границы системы типа C++ и, вероятно, должны пересмотреть свой дизайн.

+0

Для всех, кто следит за вами, в зависимости от вашего приложения @Wintermute показал мне, как использование 'std :: tuple' может решить мою проблему, хотя я думаю, что это не универсальное решение. –

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