2

I want to support one of two possible signatures of the constructor of the class T when creating its instance in the create(...) function below:

template <class Т, typename... Args>
T* create(Special* s, Args&&... args) {
  T* t = 
    // If such a constructor exists, this:
    new T(s, std::forward<Args>(args)...);
    // Otherwise, this:
    new T(std::forward<Args>(args)...);
}

I tried a few monstrous template constructions that did not cut it. The solution for resolving a member function involves SFINAE-failing a decltype of a member function, but this is not apparently possible with a constructor, as it does not have a signature type of its own.

Is this even possible in C++11, and is there any library support?

Community
  • 1
  • 1

2 Answers2

5

Just use std::is_constructible:

namespace detail
{
template<typename T, typename... Ts>
auto create(std::true_type, Special* s, Ts&&... args) {
    return new T(s, std::forward<Ts>(args)...);
}

template<typename T, typename... Ts>
auto create(std::false_type, Special*, Ts&&... args) {
    return new T(std::forward<Ts>(args)...);
}

}

template<class T, typename... Args>
T* create(Special* s, Args&&... args) {
    using tag = is_constructible<T, Special*, Args...>;
    return detail::create<T>(tag{}, s, std::forward<Args>(args)...);
}

live demo

krzaq
  • 16,240
  • 4
  • 46
  • 61
4
template <class Т, typename... Args>
T* create_impl(std::true_type, Special* s, Args&&... args) {
  return new T(s, std::forward<Args>(args)...);
}
template <class Т, typename... Args>
T* create_impl(std::false_type, Special*, Args&&... args) {
  return new T(std::forward<Args>(args)...);
}

template <class Т, typename... Args>
T* create(Special* s, Args&&... args) {
   T* t = create_impl<T>(std::is_constructible<T, Special*&, Args&&...>{},
                         s, std::forward<Args>(args)...);
   // ...
   return t;
}
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • I like this little `&` touch at the end of `Special*`! :) – kkm inactive - support strike Oct 19 '16 at 01:39
  • @kkm does it matter if you don't forward `s` though? – krzaq Oct 19 '16 at 02:23
  • @krzaq: You are probably right. Now I am confused. T.C., could you please clarify this? – kkm inactive - support strike Oct 19 '16 at 02:42
  • @kkm You are calling the constructor with a `Special*` lvalue (`s`), therefore the `is_constructible` check should be for a `Special*` lvalue. – T.C. Oct 19 '16 at 02:46
  • @T.C. wouldn't it make the behaviour for a constructor with `Special*` out parameter counter-intuitive? – krzaq Oct 19 '16 at 02:58
  • @krzaq: Oh, I deleted my previous silly comment. Now I see your point. Looks like I do not like the little `&` at the end any more! – kkm inactive - support strike Oct 19 '16 at 03:08
  • @krzaq Then change the actual call to use an rvalue. The whole point is that the check should match the call. – T.C. Oct 19 '16 at 03:09
  • @kkm [here](http://melpon.org/wandbox/permlink/KrCRfiWOlMXJpBJ3)'s a demo of both. Like or not, it's a good point to consider (though if you wanted it, it'd probably be better to make `s` a deduced type and `enable_if` for `decay_t == Special*`) – krzaq Oct 19 '16 at 03:09
  • @T.C. and you're calling `create` with a copy of a pointer, which is kind of my point ;) – krzaq Oct 19 '16 at 03:10
  • 1
    @krzaq With an *lvalue* referring to a copy. If you are asking "does this call compile", then your actual call should match the question you are asking. – T.C. Oct 19 '16 at 03:12
  • @T.C. then I guess it's the question of what you're going to ask for. In this case I'd rather ask "are you going to accept a copy of my pointer?" instead of "are you going to accept exactly the type `s` is?", but that's up to the user ultimately. – krzaq Oct 19 '16 at 03:16