3

Let me first start off by noting the very similar question here: Detecting constexpr with SFINAE. The difference is that in this question, the detection method works to detect a static method of a class.

I am trying to detect if something can be constexpr copy constructed. I'm quite close, here's what I've got:

template <class T>
constexpr int return_int(T t) {  return 0; }

template <class T>
T& unmove(T&& t) { return t; }

template <class ... T>
using void_t = void;

template <class T, class = void>
struct is_constexpr_copy_constructible : std::false_type {};

template <class T>
struct is_constexpr_copy_constructible<T, void_t<
                                              std::integral_constant<int, 
                                                  return_int(unmove(T{}))
                                              >
                                          >> : std::true_type {};

The logical progression of ideas in this solution is as follows:

  1. Only constant expression integers can be used for integer template parameters.
  2. The result of a function call is only considered constexpr if the function is constexpr and all of its parameters are constexpr.
  3. Passing something by value will entail making a copy.

So I write the function return_int which gives me a constexpr integer iff a constexpr expression of type having a constexpr copy constructor is passed. unmove just ensures that the copy constructor rather than the move constructor is called.

The problem is that in order to get an expression in the first place, I have to create my type. I cannot use declval for this as would be standard in TMP, because this is not an unevaluated context; return_int will actually be evaluated at compile time to compute the type. So I am stuck with a meta-function that detects whether a type is constexpr copy constructible AND constexpr default constructible.

This isn't the end of the world per se as these things tend to overlap, but it's not ideal. Is there any way around this? Fundamentally it boils down to:

  1. I don't see any way to verify if something is constexpr in an unevaluated context.
  2. In an evaluated context, I don't see any way to get an instance of the type I'm testing in order to try to make a copy without calling a constructor.

Note that in the similar question I linked, this simply isn't an issue because it is checking static methods, and therefore just doesn't need an instance.

Help?

Community
  • 1
  • 1
Nir Friedman
  • 17,108
  • 2
  • 44
  • 72
  • Don't you need to make `unmove` be a constexpr function also? – Chris Beck Feb 07 '16 at 05:46
  • Here's a thought: Maybe you should hew more closely to what the standard library does for the normal `std::is_copy_constructible`? For that, they check if `std::is_constructible` is true, basically. And `std::is_constructible` is supposed to check if "If the variable definition `T obj(std::declval()...);` is well-formed..." Basically what you want is `std::is_constexpr_constructible` which should check if `constexpr T obj(std::declval()...);` is well-formed. I don't see that the issue you described is not also encountered and overcome in `std::is_constructible` impl. – Chris Beck Feb 07 '16 at 06:10
  • Note also, this approach may be helpful? http://stackoverflow.com/questions/13299394/is-is-constexpr-possible-in-c11 – Chris Beck Feb 07 '16 at 06:29
  • @ChrisBeck Thanks for pointing that out. I actually came across this noexcept technique a few hours after I asked the question, but I figured I'd wait to see what else came up. I suppose I'll post what I've got so far. – Nir Friedman Feb 08 '16 at 15:51
  • @ChrisBeck Unfortunately, I wasn't able to leverage noexcept the way I wanted, and had to ask a new question: http://stackoverflow.com/questions/35276564/constexpr-decltype – Nir Friedman Feb 08 '16 at 18:29
  • Thanks for posting the link, I certainly learned something from it – Chris Beck Feb 08 '16 at 22:48

0 Answers0