Let's say with two attributes and some dispatching tags ( Demo at Coliru ). First, define the attributes that determine if T be called with the specified argument types:
template <typename T, typename... Args> struct callable_with_args_ { template <typename U=T> static auto test(int) -> decltype((void)std::declval<U>()(std::declval<Args>()...), std::true_type()); static auto test(...) -> std::false_type; using type = decltype(test(0)); }; template <typename T, typename... Args> using callable_with_args = typename callable_with_args_<T, Args...>::type;
or without arguments:
template <typename T> struct callable_without_args_ { template <typename U=T> static auto test(int) -> decltype((void)std::declval<U>()(), std::true_type()); static auto test(...) -> std::false_type; using type = decltype(test(0)); }; template <typename T> using callable_without_args = typename callable_without_args_<T>::type;
Then do a two-level send tag to get the priority you want:
template < class T > void update_callable_no_args(std::false_type, const std::vector<T>&) {} template < class T > void update_callable_no_args(std::true_type, const std::vector<T>& objects) { for (auto&& i : objects) { i(); } } template< class T, class... Args > void update_callable_args(std::false_type, const std::vector<T>& objects, Args&&... ) { update_callable_no_args(callable_without_args<T const&>(), objects); } template< class T, class... Args > void update_callable_args(std::true_type, const std::vector<T>& objects, Args&&... args ) { for (auto&& i : objects) { i(args...); } } template< class T, class... Args > void update_callable( const std::vector<T>& objects, Args&&... args ) { using callable = callable_with_args< T const&, typename std::add_lvalue_reference<Args>::type... >; update_callable_args(callable(), objects, std::forward<Args>(args)...); }
Note that I force argument types to lvalue reference values to avoid any of the arguments to the "eat" rvalue link to make subsequent calls to view the moved objects. If you want r-values to be moved, remove the coercion in update_callable :
using callable = callable_with_args< T const&, Args&&... >;
and forward them to each callee in update_callable_args :
for (auto&& i : objects) { i(std::forward<Args>(args)...); }
VS2013, at least, seems to be compiling it correctly .