简体   繁体   中英

template with lambda as unique default parameter on each instantiation

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] :

(8.4) ― a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, or

(8.5) ― the interpretation of such a construct in the hypothetical instantiation is different from the interpretation of the corresponding construct in any actual instantiation of the template . [ Note : This can happen in situations including the following:

(8.5.1) ― a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is performed, or

(8.5.2) ― lookup for a name in the template definition found a using-declaration, but the lookup in the corresponding scope in the instantiation does not find any declarations because the using-declaration was a pack expansion and the corresponding pack is empty, or

(8.5.3) ― an instantiation uses a default argument or default template argument that had not been defined at the point at which the template was defined, or

(8.5.4) ― constant expression evaluation within the template instantiation uses

(8.5.4.1) ― the value of a const object of integral or unscoped enumeration type or

(8.5.4.2) ― the value of a constexpr object or

(8.5.4.3) ― the value of a reference or

(8.5.4.4) ― the definition of a constexpr function, and that entity was not defined when the template was defined, or

(8.5.5) ― a class template specialization or variable template specialization that is specified by a non-dependent simple-template-id is used by the template, and either it is instantiated from a partial specialization that was not defined when the template was defined or it names an explicit specialization that was not declared when the template was defined. end note ]

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM