0

I have a function template, and a class template:

template<typename T>
T testFunction(T argOne, T argTwo) { //Implementation }

template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
class testClass { //Implementation }

I want to limit the function to only accepting arithmetic types AND this one (though possibly more in the future) custom class template.

For just the arithmetic requirement this works fine:

template<typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
T testFunction(T argOne, T argTwo) { //Implementation }

but does not include the class template. So, I figured I'd simply make a custom type trait:

template<typename T>
constexpr bool is_valid_v = std::is_arithmetic_v<T> || std::is_same_v<T, testClass>;

template<typename T, std::enable_if_t<is_valid_v<T>, int> = 0>
T testFunction(T argOne, T argTwo) { //Implementation }

but this causes the compiler to complain with

use of class template 'testClass' requires template arguments 

because it can't implicitly handle the type used for the template class when the trait template is declared this way. So, while the following compiles:

template<typename T>
constexpr bool is_valid_v = std::is_arithmetic_v<T> || std::is_same_v<T, testClass<int>> ||
                                                       std::is_same_v<T, testClass<long>> ||
                                                       std::is_same_v<T, testClass<float>> || 
                                                       //...;

template<typename T, std::enable_if_t<is_valid_v<T>, int> = 0>
T testFunction(T argOne, T argTwo) { //Implementation }

it is undesirable because I'd have to include a condition for every type the template class can use (everything under std::is_arithmetic).

I tried overloading the type trait like so:

template<typename T>
constexpr bool is_valid_v = std::is_arithmetic_v<T>;

template<template<typename> class T>
constexpr bool is_valid_v = std::is_same_v<T, NII>;

and while both of those compile fine, I still get

candidate template ignored: requirement 'is_valid_v<my_namespace::testClass<long, 0> >' was not satisfied [with T = my_namespace::testClass<long, 0>]

when trying to use testClass<long> (or any type) with testFunction.

How can I create a type trait constexpr with a "wildcard" so that I can achieve:

constexpr bool is_arithmetic_v = std::is_arithmetic_v<T> || std::is_same_v<T, NII<...>>;

without having to type out a case for every type testClass can be instantiated with? I'm fairly certain what I am aiming for is possible but that I just can't figure out the semantics for it.

EDIT: As @NathanOliver marked this post is almost a duplicate of Check if class is a template specialization? [duplicate]; however, that post doesn't show how to use its answer with enable_if and a custom template class. If I implement the answer in that post:

template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};

template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};

I can then modify my function template to be:

template<typename T, std::enable_if_t<is_specialization<T,std::vector>::value, int> = 0>
T testFunction(T argOne, T argTwo)

but as soon as I swap out std::vector with testClass I get:

error: template template argument has different template parameters than its corresponding template template parameter

Also, how can I create the shortcut is_specialization_v that makes use of ::value and returns a bool? I am unsure how to use the arguments provided in

template <template <class...> class Template, class...Args>

to achieve this.

EDIT 2: The error with the solution in the other question seems to be because my class template has an enable_if statement itself. If I remove the requirement so it is just template<typename T> then testClass works in the is_specialization function. This won't work though because I need that enable condition on testClass.

These small, but significant differences (using all of these particular features at once) are why I asked this question and why it is not quite a duplicate.

oblivioncth
  • 315
  • 3
  • 11
  • @Fureeish this gives `error: use of template template parameter 'Template' requires template arguments` which is similar to what I was getting when I attempted implementing the shortcut myself. – oblivioncth Sep 19 '19 at 22:15
  • @Fureeish Unfortunately, this gives the same error. I was trying to use constexpr bool and couldn't avoid this error no matter how I used the arguments. A different compiler notes: `type/value mismatch at argument 1 in template parameter list for 'template class Template> struct is_specialization' 12:70: error: expected a type, got 'Template' 12:70: error: type/value mismatch at argument 2 in template parameter list for 'template class Template> struct is_specialization' 12:70: error: expected a class template, got 'Args'` – oblivioncth Sep 19 '19 at 22:51
  • @Fureeish It shouldn't be, as the error is thrown from the statement alone, not when I am trying to use the function. This compiles alone and when I use it with enable_if (testing with std::vector for now), but I'm not convinced it is functionally correct: `template – oblivioncth Sep 19 '19 at 22:57
  • @Fureeish Didn't catch the hyperlink before sorry, guess I'm blind. When I [try to use that template](https://godbolt.org/z/ZC40Im) in your example it doesn't seem to work unless I'm using it wrong. [Another online compiler](https://onlinegdb.com/HyVv49WvH) throws a similar error to the one I'm getting with MSVC in Qt creator just from the declaration alone (the error I mentioned above) – oblivioncth Sep 19 '19 at 23:47
  • After getting faimilar with your code, I must admit that I was wrong and, unfortunately, I do not know how to simplify the calls. I [asked a question](https://stackoverflow.com/questions/58027884/type-traits-v-variable-template-utility-order-fails-to-compile) in this regard. I also deleted my previous comments since it was getting a little too chatty. – Fureeish Sep 20 '19 at 11:54
  • 1
    Solution: `template class Template> constexpr bool is_specialization_v = is_specialization::value;`. Simple, but I overlooked it. – Fureeish Sep 20 '19 at 12:09
  • @Fureeish Thanks for staying commuted. Exactly what I needed and takes care of the second half of my question. – oblivioncth Sep 22 '19 at 03:09

0 Answers0