简体   繁体   中英

Compiler discrepancy with simple meta function

When I try to use the following meta function to retrieve the first type of a tuple, the code can be compiled with GCC but not with Clang. I have two questions regarding the little snippet.

  1. Is this legal C++ code? And why? Or why not?
  2. Is there a workaround (or correct alternative) which works for both compilers?
#include <tuple>

template<typename>
struct first_type;

template<template<typename, typename...> typename T, typename T1, typename... Ts>
struct first_type<T<T1, Ts...>>
{ using type = T1; };

template<typename T>
using first_type_t = typename first_type<T>::type;

using tuple_type1 = first_type_t<std::tuple<int, int, double>>;

Live example


As requested, the error message generated by Clang:

<source>:12:1: error: implicit instantiation of undefined template
    'first_type<std::tuple<int, int, double>>'
using first_type_t = typename first_type<T>::type;
^
<source>:14:21: note: in instantiation of template type alias
    'first_type_t' requested here
using tuple_type1 = first_type_t<std::tuple<int, int, double>>;
                    ^
<source>:4:8: note: template is declared here
struct first_type;
       ^

In conclusion:

  • As answered by IWonderWhatThisAPIDoes; to circumvent the compiler discrepancy completely, simply drop the requirement of the templated template argument to have at least a single type.
  • As pointed out by Nathan Oliver; if you need the first type of a tuple (or really any type given an index), simply use the std::tuple_element meta function instead.
  • As pointed out by HolyBlackCat; it seems the ruling that Clang enforces regarding templated template arguments, is stricter than technically required by the standard. This behavior can be disabled by passing the -frelaxed-template-template-args compiler flag.

Temporarily changing your struct declaration to (thus getting rid of the incomplete type):

template<typename>
struct first_type {};

Changes the error you get to:

no type named 'type' in 'first_type<std::tuple<int, int, double>>'

This gives us valuable information: the compiler chose the generic version of the template, implying that Clang does not consider tuple to be a valid template<typename,typename...>class to instantiate first_type with (which is true - template<typename,typename...>class takes one or more parameters, while a tuple can also be empty). As pointed out in the comments, this does not matter to the standard itself, but Clang rejects it on purpose .

A tuple is a template<typename...>class , so...

template<template<typename...> typename T, typename T1, typename... Ts>
struct first_type<T<T1, Ts...>> {
    using type = T1;
};

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