Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type_traits *_v variable template utility order fails to compile

Having seen this answer, I tried to come up with a variable template utility to the code from it:

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 {};

And implement it like so:

template <template <class...> class Template, class... Args>
constexpr bool is_specialization_v = is_specialization<Template<Args...>, Template>::value;

because that's how I saw similar utilities to be implemented in the header file of <type_traits>. E.g.:

template <typename _Tp, typename _Up>
  inline constexpr bool is_same_v = is_same<_Tp, _Up>::value;
template <typename _Base, typename _Derived>
  inline constexpr bool is_base_of_v = is_base_of<_Base, _Derived>::value;
template <typename _From, typename _To>
  inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value;

etc. (GCC 8.2.0 implementation from MinGW)

But the problem is that, while the ::value syntax seems to work, the *_v syntax does not:

int main() {
    bool foo = is_specialization<std::vector<int>, std::vector>::value; // No problem
    bool bar = is_specialization_v<std::vector<int>, std::vector>;      // compilation error!

    std::cout << foo << ' ' << bar;
}

This produces the following error:

error: type/value mismatch at argument 1 in template parameter list for 'template<template<class ...> class Template, class ... Args> constexpr const bool is_specialization_v<Template, Args ...>'
 bool bar = is_specialization_v<std::vector<int>, std::vector>;      // compilation error!
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note:   expected a class template, got 'std::vector<int>'
error: type/value mismatch at argument 2 in template parameter list for 'template<template<class ...> class Template, class ... Args> constexpr const bool is_specialization_v<Template, Args ...>'
expected a type, got 'vector'

Why is that? To be honest, the error seems fair to me and got me thinking how exactly does the code in the aforementioned answer work. It expects a class template and a parameter pack, but it's given a class, then a pack. On the other hand, it's specialised on the combination of those two types and it confuses me slightly. I would like to know:

  • What is the deduction process here? The linked answer does not go in detail on how the code works.
  • How to introduce the *_v variable template utility in this case?
like image 778
Fureeish Avatar asked Sep 20 '19 11:09

Fureeish


People also ask

What are variable templates in C++14?

C++14 introduced a new feature, variable templates. As their name indicates, they are variables, parametrized with a type. This allows us to write type traits without using a type alias or struct, meaning we have a real value instead of a type. If we rewrite our is_float traits with variable templates, we have the following:

Why do I get gcc5 family not-helpful with variable templates?

If you plan to use variable templates inside a template, such as something like this: You will encounter a not-helpful at all error message with GCC5 family, such as: It comes from a bug in the handling of variable templates as dependent names.

What are the traits used in templated code?

Often if you write templated code, you have to write and use a lot of different traits. In this article, I'll focus on the traits that are representing values, typically a boolean value.

What is a type trait?

A type trait is a simple template struct that contains a member constant, which in turn holds the answer to the question the type trait asks or the transformation it performs. For example, let's take a look at std::is_floating_point, one of the many type traits defined by the C++ Standard Library in the <type_traits> header:


1 Answers

Let's compare the template parameters of the varaible...

template <template <class...> class Template, class... Args>
constexpr bool is_specialization_v = is_specialization<Template<Args...>, Template>::value;

to the arguments

is_specialization_v<std::vector<int>, std::vector>

You declared it to accepts first, a template, but then you pass a type. Then you declared it to accept a type pack, but now you pass a template. The problem is that you got confused and implement the variable as one does a specialization of the primary trait. It doesn't accept parameter to pass as arguments to place in the specialization. It needs to accept the same parameters as the primary, and just forward them:

template <class T, template <class...> class Template>
constexpr bool is_specialization_v = is_specialization<T, Template>::value;
like image 83
StoryTeller - Unslander Monica Avatar answered Oct 21 '22 21:10

StoryTeller - Unslander Monica