Haskell では、引数のない関数は単なる値です。呼び出すのではなく、使用するだけです。副作用がないので、目に見える違いはありません。
OCaml には、パラメータのない関数はありません。そのようなものを取得するには、ダミーのユニット引数を追加する必要があります。
C++ ではそうではありません。C++ は、Haskell や OCaml とは異なり、 と の明確な違いを維持しf
ていf()
ます。bind
を追加することでいつでも後者に変えることができるため、前者が得られます()
。独自のラッパーを作成bind
して、それを非常に簡単に行うことができます。逆に行くのは少し難しいでしょう。
このようなラッパーの可能な実装は次のとおりです。
#include <functional>
#include <utility>
#include <iostream>
template <typename T>
struct is_noargs_callable {
private:
typedef char(&yes)[1];
typedef char(&no)[2];
template<typename U>
static yes test(decltype((std::declval<U>())())*);
template<typename>
static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
template <typename T>
struct is_noargs_callable<T()> {
static const bool value = true;
};
template <typename T>
struct is_noargs_callable<T(...)> {
static const bool value = true;
};
template <typename T>
auto call_me_if_you_can(T t) -> typename std::enable_if<is_noargs_callable<T>::value, decltype(t())>::type
{
return t();
}
template <typename T>
auto call_me_if_you_can(T t) -> typename std::enable_if<!is_noargs_callable<T>::value, T>::type
{
return t;
}
template <typename... Args>
auto apply(Args&&... args) -> decltype(call_me_if_you_can(std::bind(args...))) {
return call_me_if_you_can(std::bind(args...));
}
// testing
void foo(int a, int b, int c) { std::cout << "foo(" << a << "," << b << "," << c << ")"; }
int main ()
{
using namespace std::placeholders;
std::cout << "zero : " ; apply(foo, _1, _2, _3); std::cout << " : " ; apply(foo, _1, _2, _3)(1,2,3); std::cout << std::endl;
std::cout << "one : " ; apply(foo, 1, _1, _2); std::cout << " : " ; apply(foo, 1, _1, _2)(2,3); std::cout << std::endl;
std::cout << "two : " ; apply(foo, 1, 2, _1); std::cout << " : " ; apply(foo, 1, 2, _1)(3); std::cout << std::endl;
std::cout << "three: " ; apply(foo, 1, 2, 3); std::cout << " : "; /* nothing to test here */ std::cout << std::endl;
}
f
ただし、この 1 か所だけでとの違いをf()
なくしても、C++ プログラミングの全体的な一貫性には貢献しません。区別が気に入らない場合は、どこでもそれを殺してください (または、Haskell を大いに活用してください)。