Created
August 28, 2013 08:06
-
-
Save gintenlabo/6363346 to your computer and use it in GitHub Desktop.
compose overloaded function in C++11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <utility> | |
namespace etude { | |
template<class... Fs> | |
struct overloaded_function_impl_; | |
template<> | |
struct overloaded_function_impl_<> { | |
template<class... Args, | |
typename std::enable_if< | |
sizeof...(Args) < 0 // always false | |
>::type* = nullptr | |
> | |
void operator()(Args...) const = delete; | |
}; | |
template<class F, class = void> | |
struct function_holder_; | |
template<class F> | |
struct function_holder_<F, | |
typename std::enable_if<std::is_class<F>{}>::type> | |
: private F { | |
using F::operator(); | |
template<class F_> | |
explicit function_holder_(F_ && f) | |
: F(std::forward<F_>(f)) { | |
} | |
}; | |
template<class R, class... Args> | |
struct function_holder_<R (*)(Args...)> { | |
explicit function_holder_(R (*f)(Args...)) | |
: f_(f) { | |
} | |
// should not be template | |
R operator()(Args... args) const { | |
return (*f_)(std::forward<Args>(args)...); | |
} | |
private: | |
R (*f_)(Args...); | |
}; | |
template<class F, class... Fs> | |
struct overloaded_function_impl_<F, Fs...> | |
: private function_holder_<F>, | |
private overloaded_function_impl_<Fs...> { | |
typedef function_holder_<F> base1; | |
typedef overloaded_function_impl_<Fs...> base2; | |
using base1::operator(); | |
using base2::operator(); | |
template<class F_, class... Fs_> | |
overloaded_function_impl_(F_ && f, Fs_&&... fs) | |
: base1(std::forward<F_>(f)), base2(std::forward<Fs_>(fs)...) { | |
} | |
}; | |
template<class... Fs> | |
class overloaded_function { | |
typedef overloaded_function_impl_<Fs...> impl_t; | |
public: | |
template<class... Fs_, | |
typename std::enable_if< | |
sizeof...(Fs) == sizeof...(Fs_) | |
>::type* = nullptr | |
> | |
overloaded_function(Fs_&&... fs) | |
: impl_(std::forward<Fs_>(fs)...) { | |
} | |
template<class... Args> | |
auto operator()(Args&&... args) | |
-> decltype(std::declval<impl_t&>()(std::forward<Args>(args)...)) { | |
return impl_(std::forward<Args>(args)...); | |
} | |
template<class... Args> | |
auto operator()(Args&&... args) const | |
-> decltype(std::declval<impl_t const&>()(std::forward<Args>(args)...)) { | |
return impl_(std::forward<Args>(args)...); | |
} | |
private: | |
overloaded_function_impl_<Fs...> impl_; | |
}; | |
template<class... Fs> | |
auto make_overloaded(Fs... fs) | |
-> overloaded_function<Fs...> { | |
return {std::forward<Fs>(fs)...}; | |
} | |
} // namespace etude | |
#include <iostream> | |
std::string hoge(char const*) { | |
return "char const*"; | |
}; | |
int main() { | |
auto f = etude::make_overloaded( | |
[] (int) -> std::string { | |
return "int"; | |
}, | |
[] (double) -> std::string { | |
return "double"; | |
}, | |
[] (void*) -> std::string { | |
return "void*"; | |
}, | |
hoge | |
); | |
std::cout << f(0) << std::endl; | |
std::cout << f(1.1) << std::endl; | |
std::cout << f(&f) << std::endl; | |
std::cout << f("hoge") << std::endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I love this, which can simplify the use of
boost::variant
a lot.Some tiny little problems:
__is_final
;overloaded_function
?overloaded_function_impl
just works fine.I recommend you to propose this to the C++ standard. We can discuss your ideas and drafts here:
https://groups.google.com/a/isocpp.org/forum/#!forum/std-proposals