C ++模板元编程:使用类型别名和继承的不同行为 [英] C++ Template Meta Programming: Different Behavior using Types Aliases vs Inheritance
问题描述
我试图逆转一个c ++ 14 std :: index_sequence
,并遇到了使用继承的原始实现的问题。我发现了一个使用本地类型别名的解决方法,但我想了解为什么原始代码不起作用。
/ p> 这是我第一次尝试取消 此支持函数打印 这个实现不能按预期工作: 输出的大小为0,没有元素: 反向使用类型别名 然后我稍微修改了我的原始代码,以使用类型别名而不是不一致。所有其他逻辑应该与第一个示例完全相同。 现在检查类型时: 我看到正确的输出: 问题 即使我找到一个解决方案,我真的想了解为什么使用继承的实现失败,而使用类型aliases行为如预期。我在gcc和Clang看到这一点,所以我怀疑在语言规范中有一些原因。 (可能相关问题: typedef vs public inheritance in c ++ meta-programming ) 首先,部分特化的匹配是使用模板参数扣除来完成的。如果部分特化的模板参数可以从提供的参数中推导出来,则部分特化被认为是匹配并且可以使用。 对于函数调用,标准中的一个特殊规则允许从派生类推导出基类模板参数,如果推断会失败(§14.8.2.1[temp.deduct.call] / p4);此规则不适用于其他情况,特别是不适用于部分特化匹配。 因此,编译器不能匹配 不使用类型别名的可能的反转实施: I was trying to reverse a c++14 Broken Reverse Using Inheritance This was my first attempt at reversing a This support function prints the contents of an This implementation unfortunately did not work as I expected: The output shows a size of 0 with no elements: Working Reverse Using Type Aliases Then I slightly revised my original code to use type aliases instead of inherence. All the other logic should be exactly the same as the first example. Now when I inspect the type: I see the correct output: Question Even though I found a solution, I would really like to understand why the implementation using inheritance fails while the one using type aliases behaves as expected. I see this in both gcc and Clang, so I suspect there some reason in the language specification. (Perhaps Related Question: typedef vs public inheritance in c++ meta-programming) First, matching of partial specializations are done using template argument deduction. If the template parameters of the partial specialization can be deduced from the the arguments supplied, the partial specialization is considered a match and can be used. For function calls, there is a special rule in the standard permitting deducing base class template parameters from a derived class if deduction would otherwise fail (§14.8.2.1 [temp.deduct.call]/p4); this rule does not apply in other situations, and in particular it doesn't apply to partial specialization matching. Hence, the compiler cannot match A possible implementation of reversal using no type aliases:
这篇关于C ++模板元编程:使用类型别名和继承的不同行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
std :: index_sequence
:
///将元素附加到index_sequence的辅助类。
///基本案例。
template< size_t,typename>
struct Append:std :: index_sequence<> {};
模板< size_t X,size_t ... XS>
struct Append< X,std :: index_sequence< XS ...>> :std :: index_sequence< XS ...,X> {};
/// std :: index_sequence的反向元素
模板< typename>
struct Reverse;
///基础案例
模板<>
struct Reverse< std :: index_sequence<>> :std :: index_sequence<> {};
template< size_t X,size_t ... XS>
struct Reverse< std :: index_sequence< X,XS ...>> :追加< X,Reverse< std :: index_sequence< XS ...>>>> {};
std :: index_sequence
:
模板< size_t ... XS>
void print_seq(std :: index_sequence< XS ...>)
{
std :: cout< size< sizeof ...(XS) :;
bool Do [] = {(std :: cout<<< XS<<,true)...}
(void)Do;
std :: cout<< std :: endl;
}
print_seq(Reverse< std :: make_index_sequence< 10>>> {});
size 0:
模板< size_t,typename>
struct AppendUsingType {
using type = std :: index_sequence<> ;;
};
template< size_t X,size_t ... XS>
struct AppendUsingType< X,std :: index_sequence< XS ...>> {
using type = std :: index_sequence< XS ...,X> ;
};
template< typename>
struct ReverseUsingType;
模板<>
struct ReverseUsingType< std :: index_sequence<>> {
using type = std :: index_sequence<> ;;
};
template< size_t X,size_t ... XS>
struct ReverseUsingType< std :: index_sequence< X,XS ...>> {
using type = typename AppendUsingType< X,typename ReverseUsingType< std :: index_sequence< XS ...>> :: type> :: type;
};
print_seq(typename ReverseUsingType< std :: make_index_sequence< 10>> :: type {});
size 10:9 8 7 6 5 4 3 2 1 0
Reverse< ; std :: index_sequence< XS ...>>< / code>与
std :: index_sequence< XS ...>
的附加
是不可行的,而是使用主模板。
template< typename,typename = std :: index_sequence< >
struct Reverse;
template< size_t ... ints>
struct Reverse< std :: index_sequence<>,
std :: index_sequence< ints ...>> :std :: index_sequence< ints ...> {};
template< size_t first,size_t ... remaining,size_t ... done>
struct Reverse< std :: index_sequence< first,remaining ...>,std :: index_sequence< done ...>>
:Reverse< std :: index_sequence< remaining ...>,std :: index_sequence< first,done ...>> {};
std::index_sequence
and ran into problems with my original implementation that used inheritance. I found a workaround using local type aliases, but I would like to understand why the original code does not work.std::index_sequence
:/// Helper class that appends an element onto an index_sequence.
/// Base case.
template<size_t, typename>
struct Append : std::index_sequence<> { };
template<size_t X, size_t... XS>
struct Append<X, std::index_sequence<XS...>> : std::index_sequence<XS..., X> { };
/// Reverse elements of a std::index_sequence
template<typename>
struct Reverse;
/// Base case
template<>
struct Reverse<std::index_sequence<>> : std::index_sequence<> { };
template<size_t X, size_t... XS>
struct Reverse<std::index_sequence<X, XS...>> : Append<X, Reverse<std::index_sequence<XS...>>> { };
std::index_sequence
:template <size_t... XS>
void print_seq(std::index_sequence<XS...>)
{
std::cout << "size " << sizeof...(XS) << ": ";
bool Do[] = { (std::cout << XS << " ", true)... };
(void) Do;
std::cout << std::endl;
}
print_seq(Reverse<std::make_index_sequence<10>>{});
size 0:
template<size_t, typename>
struct AppendUsingType {
using type = std::index_sequence<>;
};
template<size_t X, size_t... XS>
struct AppendUsingType<X, std::index_sequence<XS...>> {
using type = std::index_sequence<XS..., X> ;
};
template<typename>
struct ReverseUsingType;
template<>
struct ReverseUsingType<std::index_sequence<>> {
using type = std::index_sequence<>;
};
template<size_t X, size_t... XS>
struct ReverseUsingType<std::index_sequence<X, XS...>> {
using type = typename AppendUsingType<X, typename ReverseUsingType<std::index_sequence<XS...>>::type>::type;
};
print_seq(typename ReverseUsingType<std::make_index_sequence<10>>::type{});
size 10: 9 8 7 6 5 4 3 2 1 0
Reverse<std::index_sequence<XS...>>
against std::index_sequence<XS...>
, the partial specialization of Append
is not viable, and the primary template is used instead.
template<typename, typename=std::index_sequence<>>
struct Reverse;
template<size_t...ints>
struct Reverse<std::index_sequence<>,
std::index_sequence<ints...>> : std::index_sequence<ints...>{};
template<size_t first, size_t...remaining, size_t...done>
struct Reverse<std::index_sequence<first, remaining...>, std::index_sequence<done...>>
: Reverse<std::index_sequence<remaining...>, std::index_sequence<first, done...>> {};