4 ms·
Yes, that's still SFINAE. Now `is_constructible_v<S<X>>` evaluates to either `true` or `false`, depending on `X` being complete or not on the point of instantia
by steerablesafe 5y ago
Yes, that's still SFINAE. Now `is_constructible_v<S<X>>` evaluates to either `true` or `false`, depending on `X` being complete or not on the point of instantiation, while with the static assert it's always `true`, but you get an error at the point where the default constructor is instantiated. The different value for `is_constructible_v<S<X>>` can cause ODR violation in this variable template itself https://eel.is/c++draft/meta#rqmts-5 https://eel.is/c++draft/meta#rqmts-5, or otherwise further down the line.
About your edit: I didn't know about that issue. Apparently it is ODR violation and ill-formed, no diagnostic required according to https://eel.is/c++draft/temp.point#7 https://eel.is/c++draft/temp.point#7 :(. I'm not happy about it.
Having said that, yours is not free from ODR violation issues.
- dataflow 5y ago> Yes, that's still SFINAE I saw it as "SFIAE" (no N) given there's no other overloads and thus you would get an error, but sure, I guess syntactically it's in an SFIANE context. > ODR violation in this variable template itself https://eel.is/c++draft/meta#rqmts-5 https://eel.is/c++draft/meta#rqmts-5, or otherwise further down the line. [...] Having said that, yours is not free from ODR violation issues. I'm not passing anything incomplete to something in <type_trait> anywhere in this code though. In fact I don't even see where it says that such UB (even if you were to deliberately pass it to is_constructible) would be an ODR violation specifically. Note the claim wasn't "it is impossible to write undefined behavior by using this snippet". The claim was just there's no ODR violation in that code. If your goal was to introduce undefined behavior in general there are about a million ways you can already do that even without this. This is just about the most benign kind of UB you can have in reality; I'm pretty darn sure no compiler is going to deliberately generate a buggy program with this snippet merely because the type was technically incomplete there. Worst case is you end up calling the wrong constructor, but you're the one writing the constructors, so you wouldn't be introducing potentially-conflicting overloads in the first place. And even in that case you would really have to deliberately go out of your way to write unrealistic code to get back a buggy program (i.e. such that the alternative constructor actually ends up doing the wrong thing). I know I've never seen this blow up in actual code. > About your edit: I didn't know about that issue. Apparently it is ODR violation and ill-formed, no diagnostic required according to https://eel.is/c++draft/temp.point#7 https://eel.is/c++draft/temp.point#7 :(. I'm not happy about it. I dare say that situation is a lot more likely to cause problems in reality than the UB you're worried about, given forward declarations + subsequent accidental name collisions are things I've written in the past. If anything I would want to mitigate against this, not that.
- steerablesafe 5y agoThere is no ODR violation in this itself either: template<class T> class S { public: // template<std::enable_if_t<((void)sizeof(T), true), bool> = false> explicit S(unsigned char *) { static_assert(sizeof(T) > 0, "oops"); } }; It was always about usage. Some constructs are easier to misuse than others.
- dataflow 5y agoMine was indeed about usage; I'm pretty sure I never claimed there's any ODR violation in that code. Whereas in your comment you specifically claimed "the different value for `is_constructible_v<S<X>>` can cause ODR violation in this variable template itself https://eel.is/c++draft/meta#rqmts-5 https://eel.is/c++draft/meta#rqmts-5", in response to which I pointed out that the quote you're referencing declares this UB without involving ODR at all. In any case, I think we're on the same page at this point; we both understand the issues and risks/benefits with both approaches. Hope the examples I provided were helpful.
- steerablesafe 5y agoYes, the quote for [meta] only specifies UB (although it should arguably be IFNDR). If yourself implemented `your::is_constructible_v`, then in translation units it instantiated differently for the same template arguments, then it would be ODR-violation according to https://eel.is/c++draft/temp.point#7.sentence-4 https://eel.is/c++draft/temp.point#7.sentence-4 .
- dataflow 5y agoFunny enough, I am actually not sure if even that is true in the way you're imagining. Bear in mind such a variable would be a constexpr inline template... which would be kind of its entire point. To violate ODR with it you'd not only have to implement your::is_constructible_v, but also use the resulting value in a non-constexpr context (I think [1] alludes to this)... which would be a rather bizarre use for a type trait called 'is_constructible_v'. Anyway, this discussion is dragging on forever, so I'm just gonna stop here and wrap this up with the following: As I see it, the only realistic way you could ever generate a buggy program with this is if you're getting nerd-sniped and desperately trying to come up with a counterexample in response to someone's challenge on HN. For practical purposes I see it as a non-issue. [1] https://eel.is/c++draft/basic.def.odr#5 https://eel.is/c++draft/basic.def.odr#5