我有以下元结构模板,用于检查特定类型(KeyType
)是否是参数包的一部分。
#include <type_traits>
#include <utility>
template<typename ...>
struct find_type : std::false_type {};
//specialization used if queried type is found
template<typename QueriedType>
struct find_type<QueriedType, QueriedType> : std::true_type {};
//specialization used if KeyType and ValueType not wrapped
template<typename QueriedType,
typename KeyType,
typename ValueType,
typename... Remaining>
struct find_type<QueriedType, KeyType, ValueType, Remaining...>
{
static const bool value =
std::conditional<find_type<QueriedType, KeyType>::value,
std::true_type,
find_type<QueriedType, Remaining...>>::type::value;
};
//specialization used if KeyType and ValueType are wrapped inside e.g. std::pair
template<typename QueriedType,
template<typename, typename> class C,
typename KeyType,
typename ValueType,
typename ...Remaining>
struct find_type<QueriedType, C<KeyType, ValueType>, Remaining...> :
find_type<QueriedType, KeyType, ValueType, Remaining...>{};
//entry point
template<typename ...>
struct entry_find_type;
template<typename QueriedType,
typename ...Remaining>
struct entry_find_type<QueriedType, std::tuple<Remaining...>> :
find_type<QueriedType, Remaining...> {};
可能有更好的方法可以做到这一点,但在使用结构时我得到了一个有趣的行为。请考虑以下代码段。在第一个范围内,我触发find_type
首先传递一个没有包装器的键值对,然后使用std::pair
传递第二个键值对。编译好了。在第二个范围内,我使用相同的键值对触发find_type
,只需使用未展开的键值对切换std::pair
。由于模糊的特化(见下文),这会产生编译器错误。
class IFirstType
{
};
class ISecondType
{
};
class IDerived : public IFirstType, public ISecondType
{
};
int main(int argc, char*argv[])
{
{ //compiles fine
typedef std::tuple<IFirstType, IDerived,
std::pair<ISecondType, IFirstType>> tuple_type;
typedef entry_find_type<ISecondType, tuple_type> query_type;
static const bool bFound = query_type::value;
}
{ //compile error
typedef std::tuple<std::pair<ISecondType, IFirstType>,
IFirstType, IDerived> tuple_type;
typedef entry_find_type<ISecondType, tuple_type> query_type;
//static const bool bFound = query_type::value; //<--- compiler error here
}
return 0;
}
编译器输出(gcc 4.9):
/tmp/gcc-explorer-compiler115628-35-8rkb3f/example.cpp: In instantiation of 'struct entry_find_type<ISecondType, std::tuple<std::pair<ISecondType, IFirstType>, IFirstType, IDerived> >':
69 : required from here
39 : error: ambiguous class template instantiation for 'struct find_type, IFirstType, IDerived>'
struct entry_find_type<QueriedType, std::tuple<Remaining...>> :
^
16 : error: candidates are: struct find_type
struct find_type<QueriedType, KeyType, ValueType, Remaining...>
^
30 : error: struct find_type, Remaining ...>
struct find_type<QueriedType, C<KeyType, ValueType>, Remaining...> :
^
39 : error: invalid use of incomplete type 'struct find_type, IFirstType, IDerived>'
struct entry_find_type<QueriedType, std::tuple<Remaining...>> :
^
5 : error: declaration of 'struct find_type, IFirstType, IDerived>'
struct find_type : std::false_type {};
^
/tmp/gcc-explorer-compiler115628-35-8rkb3f/example.cpp: In function 'int main(int, char**)':
69 : error: 'value' is not a member of 'query_type {aka entry_find_type, IFirstType, IDerived> >}'
static const bool bFound = query_type::value; //<--- compiler error here
^
Compilation failed
live example at gcc.godbolt.org
如果我理解正确,编译器应该在两种情况下选择相同的模板特化,但第二种情况不能编译。我希望编译器为std::pair
的两种用法选择专用的模板模板参数版本。有人能告诉我我做错了吗?