boost::bind, std::bind и перегруженные функции

Я заметил, что boost::bind, в отличие от std::bind, может работать с перегруженными функциями, когда одна из этих функций не имеет параметров. Я прав? Это задокументировано?

#include <boost/bind.hpp>

#include <functional>
#include <iostream>

void foo()
{
    std::cout << "::foo() \n";
}

void foo(int)
{
    std::cout << "::foo(int) \n";
}

int main()
{
    boost::bind(foo)(); // Ok
    boost::bind(foo, 0)(); // Ok

    // std::bind(foo)(); // Error
    // std::bind(foo, 0)(); // Error
}

#include <boost/bind.hpp>

#include <functional>
#include <iostream>

void foo(int)
{
    std::cout << "::foo(int) \n";
}

void foo(const std::string&)
{
    std::cout << "::foo(const std::string&) \n";
}

int main()
{
    // boost::bind(foo, 0)(); // Error
    // boost::bind(foo, "str")(); // Error

    // std::bind(foo, 0)(); // Error
    // std::bind(foo, "str")(); // Error
}

person FrozenHeart    schedule 07.10.2013    source источник


Ответы (3)


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

std::bind — это функция C++11, реализованная с помощью вариативных шаблонов.

boost::bind был реализован для C++03, а это означает, что он опирается на большое количество перегруженных шаблонов функций.

Они сильно различаются в деталях реализации, и поэтому я бы предположил, что любая разница между их поведением является следствием этого, а не преднамеренной и определенной разницей.

В документации Boost указано только следующее: «Попытка связать перегруженную функцию обычно приводит к ошибке, поскольку невозможно определить, какая перегрузка предназначена для связывания».

В моей книге это означает, что документы Boost сообщают вам, что это «неопределенное поведение», независимо от того, будет ли это работать (компилировать) или даже выбирать правильную перегрузку.

И, насколько мне известно, вы всегда должны использовать явное приведение типов (static_cast) для исправления сигнатуры перегрузки, которую вы хотите выбрать. Это верно как для boost::bind, так и для std::bind, и в этом смысле обе реализации совпадают.

person Mikael Persson    schedule 07.10.2013

Это несколько задокументировано как часть «Интерфейсы» -> «Синопсис», где перечислены перегрузки. Как вы можете видеть, Boost не использует шаблоны с переменным числом аргументов, поэтому, когда они перегружены, в явном виде это:

template<class R> unspecified-2 bind(R (*f) ());
template<class F, class A1> unspecified-3-1 bind(F f, A1 a1);
template<class R, class B1, class A1> unspecified-4 bind(R (*f) (B1), A1 a1);

компилятор предпочитает перегруженные версии с пустым списком аргументов другим, поскольку они лучше подходят. Хотя я не думаю, что это было сделано намеренно.

person Daniel Frey    schedule 07.10.2013

Первый случай хорошо компилируется в MSVC10 как с std, так и с boost (поскольку MSVC10 не поддерживает вариативные шаблоны, поэтому std::bind реализован аналогично boost::bind).

Второй случай не будет компилироваться, потому что bind может разрешать перегрузки с разной арностью, но не может разрешать перегрузки, которые различаются только типами аргументов.

person Igor R.    schedule 07.10.2013