I'm looking for a way to automatically make default template parameter be unique each time a template is instantiated. Since unnamed function objects created by lambda expressions have different types I thought of adopting them somehow. With recent changes to standard daft removing "A lambda-expression shall not appear in ... a template-argument" restriction (see Wording for lambdas in unevaluated contexts) it seemed like a good idea. So I wrote the following kinda working snippet that compiles on recent gcc and clang:
#include <type_traits>
template<void ( * ) (void) = [](){}> class
unique final {};
static_assert(false == ::std::is_same_v<unique<>, unique<>>);
int main()
{
return 0;
}
Is this a viable approach or one of those "ill-formed, no diagnostic is required" cases?
Some additional context: I want to use this to implement Ada-style strong type definitions that should work in a single translation unit without manually inventing unique tags that would be otherwise unused:
struct _tag_WowInt {};
using Int = type<int, _tag_WowInt>;
struct _tag_SoUnique {};
using DifferentInt = type<int, _tag_SoUnique>;
Upd1: I would like to mention that approaches involving __COUNTER__
or similar macros won't work in general case because they will be expanded by preprocessor only once and won't yield unique types when used inside of template for example.
I believe that you are right, it seems to me that is "ill-formed, no diagnostic required". I think this is covered by [temp.res/8.4] and [temp.res/8.5]:
Even though your use case is not explicitly listed in the examples of the note, in my understanding the requirement implies that
unique<>
must refer to the same thing throughout the whole program, otherwise it is ill-formed, no diagnostic required.This was CWG1850. The Committee appear to dislike this kind of stateful meta-programming. The
constexpr
counter no longer works in newer versions of the compilers.