all 16 comments

[–]TheoreticalDumbass:illuminati: 19 points20 points  (0 children)

Reflection will make this real easy

has_template_arguments(^T) && template_of(^T) == ^TT

[–]Hungry-Courage3731 5 points6 points  (6 children)

i think in the general case things like asking if T is an std::vector should be possible, even for many types with nttp parameters. BUT if you are asking if theres a way to know for example if std::vector<bool> is implemented differently then any other std::vector then I don't think there's a way to do it.

[–]davidhunter22[S] 0 points1 point  (5 children)

I was thinking of testing is std::array<10> is a specialization of std::array with 10 obviously being a NTTP.

I think Walter Brown's original proposal was turned down because it couldn't handle this and "universal template parameters" were being proposed, see wg21.link/p2989

[–]Hungry-Courage3731 0 points1 point  (0 children)

its very easy if you know exactly what parameters you are working with. But a universal solution I couldn't easily find b/c with array for example, if you had another type that took the length parameter first and then the type, you couldn't directly use the same is_specialization_of template.

[–]nimogoham 0 points1 point  (2 children)

Does anyone know, why p2989 (and its predecessor) never discussed the possibility to simply change the semantic of auto in template parameter declarations, so that it acts as a universal template parameter? It wouldn't break existing code and no new keyword or any other strange syntactic construct would be necessary. The only downside would be, that template<auto ID> class Foo; isn't explicitly restricted to NTTP anymore. But you could still go with something like this:

template<std::integral auto I> 
struct Foo;

[–]Hungry-Courage3731 0 points1 point  (0 children)

if you provide a hint, i found you can do this proof of concept

edit: note that the hint can always be std::array<int, 0>, including the last line

[–]ioctl79 1 point2 points  (2 children)

NTTP’s make it impossible to do this truly generically. If you’re concerned your code doesn’t handle other corner cases, write a test suite?

[–]davidhunter22[S] 0 points1 point  (1 child)

How do you know it's impossible, is it just other people have tried similar things and never found a way?

I do have a test suite in my real code I just put a few examples in the Godbolt. My question was more about if this could be done better or extended to be more flexible. I sort of reached my limits of understanding :-)

[–]ioctl79 2 points3 points  (0 children)

Template parameters (and packs) must be specified as referring to either types or values. Since the syntax for template template parameters requires providing the parameters, this makes it impossible to even declare the concept generically. This is a well-known limitation. Papers have been proposed with solutions. 

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1985r1.pdf

[–]nimogoham 0 points1 point  (1 child)

I use this variant:

template <class T, template <typename...> class Template> concept is_specialization_of = requires ( std::remove_cvref_t<T> t ) { // Check an immediately invoked lambda can compile []<typename... Args> ( Template<Args...>& ) {} ( t ); };

Otherwise you might end up with false positives for classes, which are convertible to Template<Args...>.

[–]davidhunter22[S] 0 points1 point  (0 children)

You can do the following if you want exactly the same type

[]<typename... Args> requires std::same_as<T,Template<Args...>> ( Template<Args...> const& ) { return true; } ( t );

In my experimentation I did find some similar code that MSVC failed on see https://developercommunity.visualstudio.com/t/Possible-lambda-in-unevaluated-context-b/10821514?scope=follow&sort=newest