当类型是一堆st向量时,我需要专门化一个可变参数模板d::
#include <iostream>
#include <vector>
#include <type_traits>
template<typename... Ts>
struct is_vector{
is_vector(Ts&...){};
static void print() {std::cout << "not vectors" <<std::endl;}
};
template<typename... Ts>
struct is_vector<std::vector<Ts>...>
{ is_vector(std::vector<Ts>&...){}
static void print() {std::cout << "vectors" << std::endl;}
};
int main()
{
auto const a3 = std::vector<double> {10., 20., 30.};
auto a4 = std::vector<int> { 1,2,3};
auto z = is_vector(a4,a3); z.print(); // print "not vectors"
auto x = is_vector(a4,a4); x.print(); // print "vectors"
return 0;
}
问题在于,当is_vector的参数包含常量和非常量向量的混合时,它使用默认类而不是专用类。当然,如果所有向量都是常量,我可以编写一个专门化,但如何处理混合是个问题。我试过这个
template<typename... Ts>
struct is_vector<typename std::remove_const<std::vector<Ts> >::type...>
{ is_vector(std::vector<Ts>&...){}
static void print() {std::cout << "vectors" << std::endl;}
};
但是编译器 (Apple clang 版本 11.0.3 (clang-1103.0.32.62) 目标: x86_64-apple-darwin21.4.0) 抛出此错误
test.cpp:13:8:错误:类模板局部特化包含一个无法推导的模板参数;这个局部特化将永远不会被使用[-Wunusule-part al-专用化]结构is_vector
分开关注。让< code>is_vector为一个输入、< code>const或其他输入工作。以此为基础构建变量版本。
例如
template<class T>
struct is_vector_struct
: std::false_type {};
template<class T, class allocator>
struct is_vector_struct<std::vector<T, allocator>>
: std::true_type {};
template<class T>
constexpr bool is_vector = is_vector_struct<std::remove_cvref_t<T>>::value;
static_assert(is_vector<std::vector<int> const&>);
对多个参数使用 fold 表达式:
template<class...Ts>
constexpr bool all_are_vectors = (is_vector<Ts> && ...);
如果您不能使用C 17,您可以使用递归来代替。
编辑:我给了你一个类型谓词,但你也想要分派。以下是我知道的基于谓词进行调度的技术。
你可以用
需要
(C 20),enable_if
(v3模拟需要
的范围),如果你想在基于类型的函数中做出决定,就像在你的例子中一样,我认为如果constexpr
是阻力最小的路径:
template<class...Ts>
void message(Ts...xs) {
if constexpr(all_are_vectors<Ts...>)
std::cout << "all vectors";
else
std::cout << "not all vectors";
}
如果您想有选择地从重载集中添加或删除某些内容,If constepr
对您没有帮助。这是所要求的
或启用_。
template<class...Ts>
void message(Ts...) { std::cout << "default message"; }
template<class T, std::size_t N>
void message(std::array<T,N>) { std::cout << "one array"; }
template<class...Ts>
requires all_are_vectors<Ts...>
void message(Ts...) { std::cout << "all vectors"; }
因为< code>requires
是一个语言级功能,所以编译器将尝试优先处理最具体的< code>requires重载。使用< code>enable_if和variadics,您需要帮助编译器解决一些问题:
template<class...Ts,
class = std::enable_if_t<!all_are_vectors<Ts...>>>
void message(Ts...) { std::cout << "default message"; }
template<class...Ts,
class = std::enable_if_t<all_are_vectors<Ts...>>>
void message(Ts...) { std::cout << "all vectors"; }
然后是标签分派。如果您有办法获得描述您的输入的虚拟标签类型,您可以使用常规函数重载来分派。这里比enable_if
或的优势是,您可以从更通用的标签类型继承更具体的标签类型。例如,
std::random_access_iterator_tag
继承自std::forward_iterator_tag
。这是它在这种情况下的样子:
struct default_tag {};
struct all_vectors_tag{};
template<class...Ts>
void message_dispatch(default_tag, Ts...) {
std::cout << "not all vectors";
}
template<class...Ts>
void message_dispatch(all_vectors_tag, Ts...) {
std::cout << "all vectors";
}
template<class...Ts>
using get_tag =
std::conditional_t<all_are_vectors<Ts...>,
all_are_vectors_tag,
default_tag>;
template<class...Ts>
void message(Ts...xs) {
message_dispatch(get_tag<Ts...>{}, xs...);
}
有了C 20概念,你可以这样做:
#include <iostream>
#include <vector>
#include <type_traits>
template<typename T>
concept Vector = std::is_same_v<
std::remove_cvref_t<T>,
std::vector<typename T::value_type, typename T::allocator_type>
>;
template<typename... Ts>
struct is_vector {
is_vector(Ts&...) {}
static void print() {std::cout << "not vectors" <<std::endl;}
};
template<Vector... Ts>
struct is_vector<Ts...> {
is_vector(Ts&...) {}
static void print() {std::cout << "vectors" << std::endl;}
};
int main()
{
auto const a3 = std::vector<double> {10., 20., 30.};
auto a4 = std::vector<int> { 1,2,3};
static_assert(Vector<decltype(a3)>);
static_assert(Vector<decltype(a4)>);
static_assert(!Vector<int>);
auto z = is_vector(a4,a3); z.print(); // prints "vectors"
auto x = is_vector(a4,a4); x.print(); // prints "vectors"
return 0;
}
请注意,根据具体情况,您还可以借此机会使用与代码使用的 std::vector
api 的子集匹配的更广泛概念来打开任何像 std::vector
一样运行的容器。这肯定是更惯用的方法。
也许我累了,但是我被这个简单的局部特化卡住了,它不起作用,因为指定模板参数: 将替换为,或没有帮助。那么这种专门化是否可能呢?
你也许注意到了,函数after和addTime的参数都是传递引用。这俩函数是纯函数,不修改接受的参数值,因此我也可以传值。 传值的好处是调用函数和被调用函数都进行了适当的封装--其中一方的修改不可能影响另一方,除非影响了返回值。 另一方面,传引用由于避免了参数的复制,往往更高效。除此之外,C++有一个优秀的特性叫做const,它能使引用参数和值参数一样安全。 If you are writing
我试图从一组可变的模板类(其中每个类都有一个非类型参数)中恢复非typename模板参数,以便在另一种类型中将它们用作整数序列。 下面的代码显示了我所拥有的。整数序列/成员序列是从元组中抄袭出来的。 和的类型是
我有一个编译器错误问题,请查看以下代码: 问题在于编译器忽略了 foo 函数上的“const”,使得对 foo 的调用非法(const int* to int*)。 严重程度代码描述项目文件行抑制状态错误C2664'ululfoo(const::类型)':无法将参数1从'const int*'转换为'const Mystrt::类型' 我在Visual Studio和gcc的5.3编译器中测试了以
受这个答案的启发,我生成了这段代码,其输出取决于编译器: 如果使用 GCC 11 编译,调用