Apologies for the slightly convoluted repro; the behavior seems to manifest when only certain templates are at play.
main.cpp
#include <type_traits>
template <typename... Ts>
struct TypeList
{
template <typename T>
static constexpr bool Contains()
{
return (std::is_same_v<T, Ts> || ...);
}
template <auto checker>
using evaluate_on_all_t =
std::integral_constant<bool,
(checker.template operator()<Ts>() || ...)>;
// Works fine
template <typename T>
static constexpr bool overlaps_v =
evaluate_on_all_t<
[]<typename U>(){return T::template Contains<U>();}
>::value;
// Fails to compile
template <typename T>
using overlaps_t =
evaluate_on_all_t<
[]<typename U>(){return T::template Contains<U>();}
>;
};
using MyTypeList = TypeList<float, int>;
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
using TypeListOverlap_t = MyTypeList::overlaps_t<TypeList<int, bool>>; // Fails to compile
int main()
{}
The relevant parts here are overlaps_v and overlaps_t. Both use a template lambda to evaluate if a TypeList T contains any relevant types. In the case of overlaps_v, a template constexpr variable, T is correctly interpreted as being a TypeList, and compiles. However, in the case of overlaps_t, a template alias, the compiler seems to get confused, and thinks T refers to the individual variadic types of the TypeList. Note that the lambdas are identical; the main difference seems to be whether a constexpr variable or an alias is being used.
Console
>clang++ -std=c++20 main.cpp
main.cpp:28:37: error: type 'float' cannot be used prior to '::' because it has no members
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:15:31: note: in instantiation of function template specialization 'TypeList<float, int>::(anonymous
class)::operator()<float>' requested here
(checker.template operator()<Ts>() || ...)>;
^
main.cpp:27:9: note: in instantiation of template type alias 'evaluate_on_all_t' requested here
evaluate_on_all_t<
^
main.cpp:33:36: note: in instantiation of template class 'TypeList<float, int>' requested here
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
^
main.cpp:28:37: error: type 'int' cannot be used prior to '::' because it has no members
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:15:31: note: in instantiation of function template specialization 'TypeList<float, int>::(anonymous
class)::operator()<int>' requested here
(checker.template operator()<Ts>() || ...)>;
^
main.cpp:27:9: note: in instantiation of template type alias 'evaluate_on_all_t' requested here
evaluate_on_all_t<
^
main.cpp:33:36: note: in instantiation of template class 'TypeList<float, int>' requested here
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
^
main.cpp:28:37: error: type 'int' cannot be used prior to '::' because it has no members
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:15:31: note: in instantiation of function template specialization 'TypeList<int, bool>::(anonymous
class)::operator()<int>' requested here
(checker.template operator()<Ts>() || ...)>;
^
main.cpp:27:9: note: in instantiation of template type alias 'evaluate_on_all_t' requested here
evaluate_on_all_t<
^
main.cpp:21:37: note: in instantiation of template class 'TypeList<int, bool>' requested here
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:33:48: note: in instantiation of static data member 'TypeList<float, int>::overlaps_v<TypeList<int, bool>>'
requested here
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
^
main.cpp:28:37: error: type 'bool' cannot be used prior to '::' because it has no members
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:15:31: note: in instantiation of function template specialization 'TypeList<int, bool>::(anonymous
class)::operator()<bool>' requested here
(checker.template operator()<Ts>() || ...)>;
^
main.cpp:27:9: note: in instantiation of template type alias 'evaluate_on_all_t' requested here
evaluate_on_all_t<
^
main.cpp:21:37: note: in instantiation of template class 'TypeList<int, bool>' requested here
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:33:48: note: in instantiation of static data member 'TypeList<float, int>::overlaps_v<TypeList<int, bool>>'
requested here
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
^
4 errors generated.
version
>clang++ --version
clang version 16.0.5
Target: i686-pc-windows-msvc
Thread model: posix
Apologies for the slightly convoluted repro; the behavior seems to manifest when only certain templates are at play.
**main.cpp**
```
#include <type_traits>
template <typename... Ts>
struct TypeList
{
template <typename T>
static constexpr bool Contains()
{
return (std::is_same_v<T, Ts> || ...);
}
template <auto checker>
using evaluate_on_all_t =
std::integral_constant<bool,
(checker.template operator()<Ts>() || ...)>;
// Works fine
template <typename T>
static constexpr bool overlaps_v =
evaluate_on_all_t<
[]<typename U>(){return T::template Contains<U>();}
>::value;
// Fails to compile
template <typename T>
using overlaps_t =
evaluate_on_all_t<
[]<typename U>(){return T::template Contains<U>();}
>;
};
using MyTypeList = TypeList<float, int>;
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
using TypeListOverlap_t = MyTypeList::overlaps_t<TypeList<int, bool>>; // Fails to compile
int main()
{}
```
The relevant parts here are `overlaps_v` and `overlaps_t`. Both use a template lambda to evaluate if a TypeList `T` contains any relevant types. In the case of `overlaps_v`, a template constexpr variable, `T` is correctly interpreted as being a TypeList, and compiles. However, in the case of `overlaps_t`, a template alias, the compiler seems to get confused, and thinks `T` refers to the individual variadic types of the TypeList. Note that the lambdas are identical; the main difference seems to be whether a constexpr variable or an alias is being used.
**Console**
```
>clang++ -std=c++20 main.cpp
main.cpp:28:37: error: type 'float' cannot be used prior to '::' because it has no members
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:15:31: note: in instantiation of function template specialization 'TypeList<float, int>::(anonymous
class)::operator()<float>' requested here
(checker.template operator()<Ts>() || ...)>;
^
main.cpp:27:9: note: in instantiation of template type alias 'evaluate_on_all_t' requested here
evaluate_on_all_t<
^
main.cpp:33:36: note: in instantiation of template class 'TypeList<float, int>' requested here
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
^
main.cpp:28:37: error: type 'int' cannot be used prior to '::' because it has no members
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:15:31: note: in instantiation of function template specialization 'TypeList<float, int>::(anonymous
class)::operator()<int>' requested here
(checker.template operator()<Ts>() || ...)>;
^
main.cpp:27:9: note: in instantiation of template type alias 'evaluate_on_all_t' requested here
evaluate_on_all_t<
^
main.cpp:33:36: note: in instantiation of template class 'TypeList<float, int>' requested here
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
^
main.cpp:28:37: error: type 'int' cannot be used prior to '::' because it has no members
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:15:31: note: in instantiation of function template specialization 'TypeList<int, bool>::(anonymous
class)::operator()<int>' requested here
(checker.template operator()<Ts>() || ...)>;
^
main.cpp:27:9: note: in instantiation of template type alias 'evaluate_on_all_t' requested here
evaluate_on_all_t<
^
main.cpp:21:37: note: in instantiation of template class 'TypeList<int, bool>' requested here
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:33:48: note: in instantiation of static data member 'TypeList<float, int>::overlaps_v<TypeList<int, bool>>'
requested here
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
^
main.cpp:28:37: error: type 'bool' cannot be used prior to '::' because it has no members
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:15:31: note: in instantiation of function template specialization 'TypeList<int, bool>::(anonymous
class)::operator()<bool>' requested here
(checker.template operator()<Ts>() || ...)>;
^
main.cpp:27:9: note: in instantiation of template type alias 'evaluate_on_all_t' requested here
evaluate_on_all_t<
^
main.cpp:21:37: note: in instantiation of template class 'TypeList<int, bool>' requested here
[]<typename U>(){return T::template Contains<U>();}
^
main.cpp:33:48: note: in instantiation of static data member 'TypeList<float, int>::overlaps_v<TypeList<int, bool>>'
requested here
constexpr bool TypeListOverlap_v = MyTypeList::overlaps_v<TypeList<int, bool>>; // Works fine
^
4 errors generated.
```
**version**
```
>clang++ --version
clang version 16.0.5
Target: i686-pc-windows-msvc
Thread model: posix
```
Apologies for the slightly convoluted repro; the behavior seems to manifest when only certain templates are at play.
main.cpp
The relevant parts here are
overlaps_v
andoverlaps_t
. Both use a template lambda to evaluate if a TypeListT
contains any relevant types. In the case ofoverlaps_v
, a template constexpr variable,T
is correctly interpreted as being a TypeList, and compiles. However, in the case ofoverlaps_t
, a template alias, the compiler seems to get confused, and thinksT
refers to the individual variadic types of the TypeList. Note that the lambdas are identical; the main difference seems to be whether a constexpr variable or an alias is being used.Console
version