Constructor gets ugly with `std::function`
So I'm refactoring an old class which essentially runs some functions in a pipeline and for the premise of the question, this particular class accepts functors as parameters in the constructors.
I have the following 3 options, ranked in order of how I like them:
- Use a trait class instead to squirrel types away and to consolidate all the different types in one place. Requires a using declaration inside the class to be really useful, and it could use some MACRO to clean it up and look real nice.
- If I put the
std::functionin the place, it makes the code look ugly. I don't think it is acceptable, but it's scalable. - If I use global
usingdirectives, it pollutes the namespace with what looks even uglier due to templates. But at least the constructors look nice. However, now it's an effort to grok for the type of the functor that ctor accepts. And it's not very flexible, unless I use option 1, in which case I might as well go all in on option 1.
Which is the preferred alternative? Do you have a better option? (And no, using #define is not an option). Any other ways I can refactor it to make my life in 2 weeks a little less hell?
Please keep in mind that there is a fair mix of CRTP thrown in the real code for fun (and speed) which makes it weird with these template parameters going round and round.
Drum-roll for the code please
namespace cpp_questions {
class dummy;
// assume class to be specialized here, declared somewhere else
template<>
class dummy_traits<dummy, class = concept_checker_dont_worry_about_it<dummy>> {
using map = wow::secret_map;
using input_details = wow::secret_struct;
using factory_functor = std::function<typename map::mapped_type(const std::string&,
std::function<void(void)>,
const input_details&,
const std::string&)>;
}; // the death is upon us with class dummy_traits<dummy, _>
template <class T>
using checking_functor = std::function<bool(const complicated_type_like_array_of_vector<typename dummy_traits<T>::map::mapped_type,
wow::secret_enum::__MAX__>&)>;
struct dummy {
using input_details = typename dummy_traits<dummy>::input_details;
dummy(// option 1: traits class
typename dummy_traits<dummy>::factory_functor generateElements,
// option 2: here (chosen a simpler type)
std::function<input_details(input_details, const input_details&)> foldItBaby,
// option 3: worst, because now I can't overload it if I'm not using a traits class
checking_functor overrideCheck = [](auto& input) -> bool {
return input[LETS_SAY_THIS_IS_COMPILE_TIME_DEFAULT].size();
}) {
// let's do boring stuff here
}
}; // the death is upon us with class dummy
} // all hail the end of namespace
NINJA-EDIT: code indent fix
3 comments · 50% upvoted · other discussions
Assuming
dummydoesn't need to store the function object, then I would make it a template class and usestatic_assertto enforce the parameter type. Ifdummy_traitsis usable beyonddummy, then CRTP would be fine. Otherwise, it's overkill since we know thatdummysatisfies the trait conditions. I generally prefer traits classes for enforcing type checks, so that's what I would use.codingate [OP] 1 points · Dec 2018
Thanks, that helps :)
Though I'd have a template parameter explosion, it's manageable and makes the rest of the code so much better.
Minor correction for anyone who comes by later. It's not
template <> template <typename T>, it'stemplate <typename T>.Cheers, Here's to moving from C99 to C++17
OmegaNaughtEquals1 1 points · Dec 2018
Whoops. Yes. That's what I get for not running it through a compiler first.
That's a very good transition!