Code works with Template Function but doesn't with Template Struct

There are 2 snippets of code: the 1st works, the 2nd doesn't

1st uses functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <typename T>
constexpr bool contains() { return false; }

template <typename T, typename First, typename... Rest>
constexpr bool contains()
{
	return std::is_same<T, First>::value || contains<T, Rest...>();
}

template <typename T, typename... Forbidden>
struct gforbidden_types
{
	static_assert(!contains<T, Forbidden...>(), "Cannot instantiate forbidden_types object with a forbidden type");

	using type = T;
};


2nd uses structs instead of functions (but the compiler doesn't like it)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

template <typename T, typename First, typename... Rest>
struct contains
{
	static constexpr bool value = std::is_same<T, First>::value || contains<T, Rest...>::value;
};

template <typename T>
struct contains<T>
{
	static constexpr bool value = false;
};

template <typename T, typename... Forbidden>
struct gforbidden_types
{
	static_assert(!contains<T, Forbidden...>::value, "Cannot instantiate forbidden_types object with a forbidden type");

	using type = T;
};


Error:
'contains': too many template arguments
Error: expected constant expression (in static_assert)

What's the problem with the second code?

N.B.: Yes, I know i can use fold expressions. However, i wanted to develop a solution for older compilers too.
Last edited on
Are you sure the first Error is the one reported? I would expect 'contains': too few template arguments since the declaration requires at least two and lines 9 and 17 may attempt to instantiate one with fewer arguments.

Does this work for you?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template <typename T, typename First=void, typename... Rest>
struct contains
{
    static constexpr bool value = std::is_same<T, First>::value || contains<T, Rest...>::value;
};

template <typename T>
struct contains<T, void>
{
    static constexpr bool value = false;
};

template <typename T, typename... Forbidden>
struct gforbidden_types
{
    static_assert(!contains<T, Forbidden...>::value, "Cannot instantiate forbidden_types object with a forbidden type");

    using type = T;
};
Are you sure the first Error is the one reported? I would expect 'contains': too few template arguments since the declaration requires at least two and lines 9 and 17 may attempt to instantiate one with fewer arguments.

Yes. To be honest I've never liked how MSVC reports template-related errors.

This is what g++ says, which is clearer:

1
2
error: wrong number of template arguments (1, should be at least 2)
 struct contains<T> on line 9

Does this work for you?

Yes, it works! Thanks!

I see you defaulted the template parameter to void, and then specialized it to return false in case it is void (which happens when the parameter pack becomes empty)

I suppose the template function version is just overloading the function, whereas with structs/classes I need specialization which uses that different syntax, right?

Last edited on
Registered users can post here. Sign in or register to post.