模板变量是否可以用作模板参数(类似于 class 模板)?
Can template variables be used as template parameters (similarly to class templates)?
C++17 为非类型模板参数提供了 auto
关键字。有没有办法将它与模板模板参数结合起来,然后可以将模板变量作为参数使用?
template <template <typename> auto X> // <-- This seems to be illegal
struct Foo
{
};
背景:
我想为 type_vector class 实现 copy_if。由于我想使用的所有条件都可以作为模板变量使用,因此实现它的一种方法是:
template <typename Container,
template <typename> auto Condition> // If this were allowed
struct copy_if;
template <typename... Ts,
template <typename> auto Condition>
struct copy_if<type_vector<Ts...>, Condition>
{
using type = decltype(
(type_vector<>{} + ... +
std::conditional_t<Condition<Ts>,
type_vector<Ts>,
type_vector<>>{}));
};
当然,我可以将所有变量包装到具有值的模板结构中,但我宁愿避免这样做。
也许额外的谓词参数(自 c++17 起可用的 constexpr lambda)确定参数是否符合您的变量模板就足够了吗?
#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
template <class T>
constexpr bool condition = true;
template <>
constexpr bool condition<int> = false;
template <class T>
struct tag {
using type = T;
};
template <class... Ts>
struct type_vector {
template <class... Ts2>
type_vector<Ts..., Ts2...> operator+(type_vector<Ts2...>);
};
template <class... Ts,
class Predicate>
auto copy_if(type_vector<Ts...>, Predicate p)
{
return decltype(
(type_vector<>{} + ... +
std::conditional_t<p(tag<Ts>{}),
type_vector<Ts>,
type_vector<>>{})){};
};
int main() {
auto predicate = [](auto x){ return condition<typename decltype(x)::type>;};
std::cout << typeid(decltype(copy_if(type_vector<int, float, double>{}, predicate))).name() << std::endl;
}
c++过滤输出:
type_vector<float, double>
编辑:
在某些情况下,使用人工标记来分派参数类型可能会被认为很麻烦。如果您想避免它,还有另一种方法。这个实际上避免了调用 lambda 的 operator()
模板,它只是实例化它来评估结果类型(应该等同于 std::true_type
或 std::false_type
):
#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
template <class T>
constexpr bool condition = true;
template <>
constexpr bool condition<int> = false;
template <class... Ts>
struct type_vector {
template <class... Ts2>
type_vector<Ts..., Ts2...> operator+(type_vector<Ts2...>);
};
template <class... Ts,
class Predicate>
auto copy_if(type_vector<Ts...>, Predicate p)
{
return decltype(
(type_vector<>{} + ... +
std::conditional_t<decltype(p(std::declval<Ts>())){},
type_vector<Ts>,
type_vector<>>{})){};
};
int main() {
auto predicate = [](auto x){ return std::integral_constant<bool, condition<decltype(x)>>{};};
std::cout << typeid(decltype(copy_if(type_vector<int, float, double>{}, predicate))).name() << std::endl;
}
C++17 为非类型模板参数提供了 auto
关键字。有没有办法将它与模板模板参数结合起来,然后可以将模板变量作为参数使用?
template <template <typename> auto X> // <-- This seems to be illegal
struct Foo
{
};
背景:
我想为 type_vector class 实现 copy_if。由于我想使用的所有条件都可以作为模板变量使用,因此实现它的一种方法是:
template <typename Container,
template <typename> auto Condition> // If this were allowed
struct copy_if;
template <typename... Ts,
template <typename> auto Condition>
struct copy_if<type_vector<Ts...>, Condition>
{
using type = decltype(
(type_vector<>{} + ... +
std::conditional_t<Condition<Ts>,
type_vector<Ts>,
type_vector<>>{}));
};
当然,我可以将所有变量包装到具有值的模板结构中,但我宁愿避免这样做。
也许额外的谓词参数(自 c++17 起可用的 constexpr lambda)确定参数是否符合您的变量模板就足够了吗?
#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
template <class T>
constexpr bool condition = true;
template <>
constexpr bool condition<int> = false;
template <class T>
struct tag {
using type = T;
};
template <class... Ts>
struct type_vector {
template <class... Ts2>
type_vector<Ts..., Ts2...> operator+(type_vector<Ts2...>);
};
template <class... Ts,
class Predicate>
auto copy_if(type_vector<Ts...>, Predicate p)
{
return decltype(
(type_vector<>{} + ... +
std::conditional_t<p(tag<Ts>{}),
type_vector<Ts>,
type_vector<>>{})){};
};
int main() {
auto predicate = [](auto x){ return condition<typename decltype(x)::type>;};
std::cout << typeid(decltype(copy_if(type_vector<int, float, double>{}, predicate))).name() << std::endl;
}
c++过滤输出:
type_vector<float, double>
编辑:
在某些情况下,使用人工标记来分派参数类型可能会被认为很麻烦。如果您想避免它,还有另一种方法。这个实际上避免了调用 lambda 的 operator()
模板,它只是实例化它来评估结果类型(应该等同于 std::true_type
或 std::false_type
):
#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
template <class T>
constexpr bool condition = true;
template <>
constexpr bool condition<int> = false;
template <class... Ts>
struct type_vector {
template <class... Ts2>
type_vector<Ts..., Ts2...> operator+(type_vector<Ts2...>);
};
template <class... Ts,
class Predicate>
auto copy_if(type_vector<Ts...>, Predicate p)
{
return decltype(
(type_vector<>{} + ... +
std::conditional_t<decltype(p(std::declval<Ts>())){},
type_vector<Ts>,
type_vector<>>{})){};
};
int main() {
auto predicate = [](auto x){ return std::integral_constant<bool, condition<decltype(x)>>{};};
std::cout << typeid(decltype(copy_if(type_vector<int, float, double>{}, predicate))).name() << std::endl;
}