3

After understanding decltype with 2 arguments I am wondering, could I just use that instead of enable_if? For example:

template <typename T>
decltype(T(), declval<bool>()) isConstructable() { return true; }

Succeeds with isConstructable<int> and fails with isConstructable<istream> on Visual Studio 2015: http://rextester.com/YQI94257 But on gcc I have to do:

template <typename T>
enable_if_t<decltype(T(), true_type())::value, bool> isConstructable() { return true; }

Should the decltype version work, or am I just exploiting a non-standard Microsoftianisim?

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • if you use traits for `std::enable_if` you can have *true* and *false* version. it is not (always) possible with `decltype`. – Jarod42 Jan 17 '17 at 14:07
  • @Jarod42 I'm actually just looking for a compile error in the event that the `decltype`/`enable_if` fails, so I wasn't intending to use this with a false specialization, though I can see how that is a use case not available to the `decltype` version. – Jonathan Mee Jan 17 '17 at 14:16
  • @JonathanMee: If you just want a compile error, just write your template code as normal. If it results in code that can't work, you get a compile error. – Nicol Bolas Jan 17 '17 at 14:43
  • @NicolBolas I'm actually interested in using this just as the actual [`is_constructable`](http://en.cppreference.com/w/cpp/types/is_constructible) is used in meta-programming. I'm just using construction as an MCVE, I actually have a function that I'm testing availability for and I *will* be using this function to force SFINAE. – Jonathan Mee Jan 17 '17 at 14:51

2 Answers2

1

The type of std::declval<bool>() is bool&&, not bool. That's where the warning comes from - true needs to be returned by reference.

Something like this should compile without a warning:

bool ok() { return true; }

template <typename T>
decltype(T(), ok()) is_constructable() { return true; }

int main() {
    cout << is_constructable<int>() << endl;
}
rustyx
  • 80,671
  • 25
  • 200
  • 267
  • Interesting, it seems that you are correct on gcc: http://ideone.com/jQnTp8 but incorrect on Visual Studio: http://rextester.com/NXBZL19003 So it seems that the `declval` implementation is the problem here. – Jonathan Mee Jan 17 '17 at 15:03
  • 1
    `decltype(T(), void(), true)` should be enough. (`void()` added to avoid evil overload of `operator ,`) – Jarod42 Jan 17 '17 at 17:52
  • @Jarod42 Good point, how would this play out in an `enable_if`? would I need to buffer with a `void` there too? How would I even handle that since `enable_if` accepts exactly 2 arguments. – Jonathan Mee Jan 17 '17 at 20:34
  • 1
    @JonathanMee: it would be `std::enable_if_t` (or in your case, with traits `std::enable_if_t::value, bool>`) – Jarod42 Jan 18 '17 at 08:54
0

As mentioned by RustyX's answer if you do:

is_rvalue_reference_v<decltype(isConstructable<int>())>

On gcc you'll get true and on Visual Studio you'll get false. So the reason this fails on gcc is that it's always undefined behavior to return an r-value reference to an object which is about to be destroyed: https://stackoverflow.com/a/29332571/2642059

Should declval return an r-value reference?

declval's return type is actually:

T&& unless T is (possibly cv-qualified) void, in which case the return type is T

Thus this is a "Microsoftianisim". Platform independent code could be accomplished by removing the declval:

template <typename T>
decltype(T(), bool()) isConstructable() { return true; }

gcc Example Visual Studio Example

Jarod42 has pointed out that T may have overloaded the , operator in which case a buffering void() will be needed:

template <typename T>
decltype(T(), void(), bool()) isConstructable() { return true; }
Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288