Variadic constexpr 类型选择器
Variadic constexpr type-selector
抱歉,这个名字太夸张了,我想创建一个 constexpr
函数,它接受可变数量的 布尔值 模板参数,以及 returns第一个 true
值的 "template index",在 C++11 中(仅欢迎 C++14 解决方案,但不会被接受为答案)。
比如调用这个函数Selector
Selector< false, false >() == 0 // none of the template argument is true
Selector< true, false, true >() == 1 // first true template argument is the first one
Selector< false, false, true, false >() == 3 // .. and here it's the third one
这个的典型用法,以及我称之为 "type-selector" 的原因是
Selector< std::is_pointer<T>::value, std::is_arithmetic<T>::value >()
我希望它成为 constexpr
的原因是用于部分模板专业化。
虽然我认为使用可变参数模板、constexpr 模板特化(对于 0 的情况)和递归(是否有可能 "consume" 模板参数,但我不确定该怎么做,像 bash 中的 shift
?),这应该是可行的。
#include <cstddef>
#include <type_traits>
template <std::size_t I, bool... Bs>
struct selector;
template <std::size_t I, bool... Bs>
struct selector<I, true, Bs...> : std::integral_constant<std::size_t, I> {};
template <std::size_t I, bool... Bs>
struct selector<I, false, Bs...> : selector<I+1, Bs...> {};
template <std::size_t I>
struct selector<I> : std::integral_constant<std::size_t, 0> {};
template <bool... Bs>
constexpr std::size_t Selector()
{
return selector<1, Bs...>::value;
}
我不满意答案不是纯粹的 constexpr
函数。所以我在递归中重新编写了它,一个 C++11 兼容的编译器将接受:
#include <cstddef>
template<std::size_t I = 1>
constexpr std::size_t selector(bool value = false){
return value ? I : 0;
}
template<std::size_t I = 1, typename ... Bools>
constexpr std::size_t selector(bool first, bool second, Bools ... others){
return first ? I : selector<I+1>(second, others...);
}
这将使用函数式语法而不是模板来调用,并且将始终是 constexpr
因为模板参数递增。
根据@CoffeeandCode 的回答,这是另一个使用 constexpr
递归按预期工作的示例:
#include <iostream>
#include <cstddef>
template<bool B0=false, bool... Bs>
constexpr std::size_t Selector( std::size_t I = 1 )
{
return B0 ? I : Selector<Bs...>(I+1);
}
template<>
constexpr std::size_t Selector<false>( std::size_t I )
{
return 0;
}
int main()
{
std::cout<< Selector() << std::endl;
std::cout<< Selector<false,false>() << std::endl;
std::cout<< Selector<true,false,true>() << std::endl;
std::cout<< Selector<false,false,true,false>() << std::endl;
}
抱歉,这个名字太夸张了,我想创建一个 constexpr
函数,它接受可变数量的 布尔值 模板参数,以及 returns第一个 true
值的 "template index",在 C++11 中(仅欢迎 C++14 解决方案,但不会被接受为答案)。
比如调用这个函数Selector
Selector< false, false >() == 0 // none of the template argument is true
Selector< true, false, true >() == 1 // first true template argument is the first one
Selector< false, false, true, false >() == 3 // .. and here it's the third one
这个的典型用法,以及我称之为 "type-selector" 的原因是
Selector< std::is_pointer<T>::value, std::is_arithmetic<T>::value >()
我希望它成为 constexpr
的原因是用于部分模板专业化。
虽然我认为使用可变参数模板、constexpr 模板特化(对于 0 的情况)和递归(是否有可能 "consume" 模板参数,但我不确定该怎么做,像 bash 中的 shift
?),这应该是可行的。
#include <cstddef>
#include <type_traits>
template <std::size_t I, bool... Bs>
struct selector;
template <std::size_t I, bool... Bs>
struct selector<I, true, Bs...> : std::integral_constant<std::size_t, I> {};
template <std::size_t I, bool... Bs>
struct selector<I, false, Bs...> : selector<I+1, Bs...> {};
template <std::size_t I>
struct selector<I> : std::integral_constant<std::size_t, 0> {};
template <bool... Bs>
constexpr std::size_t Selector()
{
return selector<1, Bs...>::value;
}
我不满意答案不是纯粹的 constexpr
函数。所以我在递归中重新编写了它,一个 C++11 兼容的编译器将接受:
#include <cstddef>
template<std::size_t I = 1>
constexpr std::size_t selector(bool value = false){
return value ? I : 0;
}
template<std::size_t I = 1, typename ... Bools>
constexpr std::size_t selector(bool first, bool second, Bools ... others){
return first ? I : selector<I+1>(second, others...);
}
这将使用函数式语法而不是模板来调用,并且将始终是 constexpr
因为模板参数递增。
根据@CoffeeandCode 的回答,这是另一个使用 constexpr
递归按预期工作的示例:
#include <iostream>
#include <cstddef>
template<bool B0=false, bool... Bs>
constexpr std::size_t Selector( std::size_t I = 1 )
{
return B0 ? I : Selector<Bs...>(I+1);
}
template<>
constexpr std::size_t Selector<false>( std::size_t I )
{
return 0;
}
int main()
{
std::cout<< Selector() << std::endl;
std::cout<< Selector<false,false>() << std::endl;
std::cout<< Selector<true,false,true>() << std::endl;
std::cout<< Selector<false,false,true,false>() << std::endl;
}