C ++如何使用vector< T>来专门化模板? [英] C++ How to specialize a template using vector<T>?
问题描述
基本上,我想使一个函数对vector(type)参数和非vector类型参数的行为有所不同.
Basicly ,I want to make a function behave differently for a vector(type) parameter and a non-vector type parameter .
#include <vector>
using namespace std;
template <typename type>
struct is_vector {
static const bool value = false;
};
template <typename type>
struct is_vector<vector<type>>
{
static const bool value = true;
};
template <typename type>
type read()
{
if (is_vector<type>::value)
{
type vec(10);
vec.front()=1;//left of '.front' must have class/struct/union
return vec;
}
else
{
return{};
}
}
int main()
{
auto i= read<int>();
}
我想在使用vector作为类型名时返回一个vector,在使用int作为类型名时返回一个int.
I want to return a vector while using vector as the typename ,return an int while using int as the typename .
但是由于is_vector(int):: value返回false,为什么我的编译器会报告'.front'的左边必须有class/struct/union"?如何使它工作?
But since is_vector(int)::value returns false ,why would my compiler reports "left of '.front' must have class/struct/union" ?How can I make it work ?
我想要实现的是正确地将字符串反序列化为vector(type)或vector(vector(type)).
What I want to achieve is to correctly deserialize a string to a vector(type) or a vector(vector(type)) .
我需要递归地调用read函数,同时传递一个多维向量作为模板参数,但是编译器禁止我这样做.
I need to recursively call the read function ,while passing a multidemonsional vector as a template parameter ,but the compiler forbids me to do it .
template <typename type>
struct is_vector {
static const bool value = false;
};
template <typename type>
struct is_vector<vector<type>>
{
static const bool value = true;
};
template <typename type>
type read(char*& str)
{
if (is_vector<type>::value)
{
type vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<type::value_type>(str);
return vec;
}
return *reinterpret_cast<type*>((str += sizeof(type)) - sizeof(type));
}
所以我尝试了专业化.
template<>
vector<int> read<vector<int>>(char*& str)
{
vector<int> vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<int>(str);
return vec;
}//works
template <typename type>
template <>
vector<type> read<vector<type>>(char*& str)
{
vector<type> vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<type>(str);
return vec;
}//don't work
我真的需要针对我使用的每种类型手动重写读取函数吗?
Do I really need to manually rewrite my read function for every kind of types I use ?
(像vector(vector(vector(vector(int(int))))?)
(like vector(vector(vector(int)))?)
推荐答案
您想要一个至少已参数化的函数模板 foo< R>
通过返回类型 R
,您需要专门的实现当 R
= std :: vector< U>
时,对于任意类型的 U
.
You want a function template foo<R>
that is parameterized at least
by return type R
, and you want a specialized implementation
when R
= std::vector<U>
, for arbitrary type U
.
foo< R>
的参数可以是什么都没有关系,因此出于说明目的我们假设没有任何东西.这是您的操作方式:
It doesn't matter what the arguments of foo<R>
may be, so for illustration
we'll assume there aren't any. Here's how you do that:
定义一个 trait 模板,如下所示:
Define a trait template as follows:
template<typename T>
struct is_vector
{
static constexpr bool value = false;
};
template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
static constexpr bool value =
std::is_same<C<U>,std::vector<U>>::value;
};
有了这个,
is_vector<T>::value
对于且仅当 T
= std :: vector< U>
(对于某些 U
)时,
在编译时为true.
will be true at compiletime if and only if T
= std::vector<U>
, for some U
.
然后在以下几行中定义 foo< R>()
的两个重载:
Then define two overloads of foo<R>()
on the following lines:
template <typename R>
std::enable_if_t<!is_vector<R>::value,R> foo()
{
// Your non-vector implementation instead of...
std::cout <<
"In non-vector specialization of `foo<R>()`\n";
return R();
}
template <typename R>
std::enable_if_t<is_vector<R>::value,R> foo()
{
// Your vector implementation instead of...
std::cout <<
"In vector specialization of `foo<R>()`\n";
return R();
}
这两个重载是互斥和共同穷举的.这当且仅当 is_vector< R> :: value
为false时,第一次重载才会成为合法代码.这仅当 is_vector< R> :: value
为true时,第二次重载才会成为合法代码.这要归功于 std :: enable_if
,您应该学习和理解的.
These two overloads are mutually exclusive and jointly exhaustive. The
first overload pans out to be legal code if and only if is_vector<R>::value
is false. The
second overload pans out to be legal code if and only if is_vector<R>::value
is true.
That's thanks to the behaviour of std::enable_if
,
which you should study and understand.
当编译器需要选择一个时,这些模板重载可以实现一些调用在您的代码中找到的 foo< type>()
,它发现恰好是重载之一为模板参数 R
插入 type
时,甚至都不会编译.如果第一个不会编译 type
是一些 std :: vector< U>
,如果 type
是 not ,则第二个不会编译一些 std :: vector< U>
.有用的是,编译器选择了可以编译的那个.这就是 SFINAE
(替换失败不是错误"),这就是您的问题的解决方案.
When the compiler needs to pick one these template overloads to implement some
call foo<type>()
that it finds in your code, it discovers that exactly one of the overloads
won't even compile when type
is plugged in for the template parameter R
. The first one won't compile if
type
is some std::vector<U>
and the second one won't compile if type
is not some
std::vector<U>
. Helpfully, the compiler picks the one that it can compile.
That's called SFINAE
("Substitution Failure Is Not An Error"),
and it's the solution of your problem.
这是一个说明性程序:
#include <vector>
#include <type_traits>
#include <iostream>
template<typename T>
struct is_vector
{
static constexpr bool value = false;
};
template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
static constexpr bool value =
std::is_same<C<U>,std::vector<U>>::value;
};
template <typename R>
std::enable_if_t<!is_vector<R>::value,R> foo()
{
// Your non-vector implementation instead of...
std::cout <<
"In non-vector specialization of `foo<R>()`\n";
return R();
}
template <typename R>
std::enable_if_t<is_vector<R>::value,R> foo()
{
// Your vector implementation instead of...
std::cout <<
"In vector specialization of `foo<R>()`\n";
return R();
}
int main()
{
auto i = foo<int>();
(void)i;
auto vc = foo<std::vector<char>>();
(void)vc;
return 0;
}
它将输出:
In non-vector specialization of `foo<R>()`
In vector specialization of `foo<R>()`
(gcc 6.1/clang 3.8, -std = c ++ 14
(gcc 6.1/clang 3.8, -std=c++14
see live)
这篇关于C ++如何使用vector< T>来专门化模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!