Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

error: class template placeholder not permitted in this context

Tags:

c++

tuples

ctad

The following snippet compiles in gcc 12.1 but not in gcc 11.1. Unfortunately, I only have gcc 11 at hand as I'm crosscompiling for a microcontroller. Is there a way to make it work? Also what is this cryptic "use 'auto' for an abbreviated function template" all about?

Demo

#include <cstdio>
#include <tuple>

template <typename T>
struct channel
{
    int a;
    T b;
};

template <typename... Channels>
struct light
{
    light(const std::tuple<Channels...>& channels)
        :   channels_ { channels }
    {
        
    }

    std::tuple<Channels...> channels_;
};

int main()
{
    light li(std::tuple{channel(2, 2), channel(2,false)});
}

Error (only in gcc 11.1):

<source>:25:14: error: class template placeholder 'std::tuple' not permitted in this context
   25 |     light li(std::tuple{channel(2, 2), channel(2,false)});
      |              ^~~
<source>:25:14: note: use 'auto' for an abbreviated function template

Interestingly, gcc 10.4 has something even different to say:

<source>:25:14: error: 'auto' parameter not permitted in this context
   25 |     light li(std::tuple{channel(2, 2), channel(2,false)});
      |              ^~~

I need a workaround that allows me to not specify all the template parameters of std::tuple as that would blow up my initializer to the point of unrecognizeability :/

like image 276
glades Avatar asked Oct 17 '25 01:10

glades


1 Answers

I need a workaround ...

light li{ std::tuple{channel(2, 2), channel(2, false)} };
//      ^                                              ^

A slightly more involved workaround could be to add deduction guides and constraints.

#include <cstdio>
#include <tuple>
#include <type_traits>
#include <string>

template <class T>
struct channel {
    int a;
    T b;
};

// deduction guide for channel:
template<class T>
channel(int, T) -> channel<std::remove_cvref_t<T>>;

// trait to check if a type is a channel
template<class> struct is_channel : std::false_type {};
template<class T> struct is_channel<channel<T>> : std::true_type {};
template<class T> static inline bool is_channel_v = is_channel<T>::value;

// require channel based template parameters
template <class... Channels>
requires std::conjunction_v<is_channel<Channels>...>
struct light {
    template<class... Chs>
    light(Chs&&... channels) : channels_{std::forward<Chs>(channels)...} {}

    std::tuple<Channels...> channels_;
};

// deduction guide for light
template<class... Channels>
light(Channels...) -> light<std::remove_cvref_t<Channels>...>;

Now using (...) to initialize the light works even in gcc 11.1:

int main() {
    channel x{ 2, std::string("Hello") };

    light li( channel(2, 2), channel(2, false), x);
}

Demo

like image 144
Ted Lyngmo Avatar answered Oct 18 '25 13:10

Ted Lyngmo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!