我正在开发一个C ++项目并尝试首次使用模板功能。我理解你如何使用模板的基本要点,但我需要知道变量的数据类型,以便我可以执行特定的操作。
例如,我的方法定义如下:
template<typename T> void increment(T data);
我需要检查变量数据包含哪种类型的数据。例如,我希望能够执行以下伪代码
template <typename T> void MyClass::increment(std::string stats, T tags)
{
if (tags of_type std::string)
{
//Perform some string manipulation
}
else if (tags of_type std::vector)
{
//Extract each string from the vector
}
else
{
//only strings or vectors are supported
}
}
答案 0 :(得分:2)
您正在寻找std::is_same
。
#include <string>
#include <type_traits>
#include <vector>
struct MyClass {
template <typename T>
void increment(std::string stats, T tags);
};
template <typename T>
void MyClass::increment(std::string stats, T tags)
{
if (std::is_same<T,std::string>::value)
{
//Perform some string manipulation
}
else if (std::is_same<T,std::vector<std::string>>::value)
{
//Extract each string from the vector
}
else
{
//only strings or vectors are supported
}
}
您绝对应该更喜欢重载但如果您不想在类体中重复函数声明并且也不想在类中内联函数,则可以对已删除的主模板使用显式特化。如果没有为此类型实现该功能,则会触发编译器错误。
#include <string>
#include <type_traits>
#include <vector>
struct MyClass {
template <typename T>
void increment(std::string stats, T tags) = delete;
};
template <>
void MyClass::increment(std::string stats, std::string tags)
{
//Perform some string manipulation
}
template <>
void MyClass::increment(std::string stats, std::vector<std::string> tags)
{
//Extract each string from the vector
}
int main() {
MyClass{}.increment(std::string{}, std::string{});
MyClass{}.increment(std::string{}, std::vector<std::string>{});
MyClass{}.increment(std::string{}, int{}); // BOOM!
}
答案 1 :(得分:2)
作为Henri Menke hinted,您需要在这里使用的不是模板,而是函数重载。模板不适合这个用例,因为模板化代码应尽可能通用 - 而且对类型分支的要求使其成为非泛型。
只是重载这些功能:
// In reality, you may want to pass both by reference
// (depends if you mutate those local variables
// in your function or not)
void MyClass::increment(std::string stats, std::string tags)
{
//Perform some string manipulation
}
void MyClass::increment(std::string stats, std::vector<std::string> tags)
{
//Extract each string from the vector
}
编辑: 在评论中,你说你想把它作为一个单一的功能来保持可读性 - 但是,我说这是个人偏好,我建议不这样做。否则,如果您的功能变得过于复杂,您可能会遇到以下问题:分支基于&#34;基于类型&#34;哪些是实际的代码流。
答案 2 :(得分:1)
如果主模板由于某种原因不足(或者只是提供常规重载,将在解析过程中的模板之前选择),您可以明确地专门化功能模板。
template<typename T> void increment(T & value) { ++value; }
void increment(MyClass & value) { value.Increment(); }
如果你传递的参数是MyClass左值,那么将选择后者。
答案 3 :(得分:1)
我需要知道变量的数据类型,以便执行特定操作。
要知道数据类型,您可以使用类型特征;标准类型特征为std::is_same
if ( std::is_same<T, std::string>::value )
或自定义自制类型特征
template <typename>
struct isVect : public std::false_type
{ };
template <typename ... Ts>
struct isVect<std::vector<Ts...>> : public std::true_type
{ };
// ....
if ( isVect<T>::value )
但是
if ( std::is_same<T, std::string>::value )
{ /* some code 1 */ }
else if ( isVect<T>::value )
{ /* some code 2 */ }
else
{ /* some code 3 */ }
(一般来说)是一个坏主意。
如果“某些代码x”包含可以独立于文字字符串的类型T
(例如日志,通过std::cout
)执行的代码,那么一切顺利。
但是,例如,如果“某些代码2”包含特定的std::vector
指令,则使用std::string
调用该函数会出现错误。因为当T
是std::string
但编译器编译它时,不执行“某些代码2”部分。
这个问题可以从引入if constexpr
if constexpr ( std::is_same<T, std::string>::value )
{ /* compiled only in std::string case */ }
else if constexpr ( isVect<T>::value )
{ /* compiled only in std::vector case */ }
else
{ /* compiled only in other cases */ }
但对于C ++ 11和C ++ 14,我能建议的最好是使用重载
void MyClass::increment (std::string stats, std::string s)
{ /* string manipulation */ }
template <typename T>
void MyClass::increment (std::string stats, std::vector<T> v)
{ /* string from vector */ }
template <typename T>
void MyClass::increment (std::string stats, T t)
{ /* no std::string and no std::vector */ }
或者,如果increment()
中有很多公共代码,请求辅助函数的不同部分
void MyClass::increment_helper (std::string s)
{ /* string manipulation */ }
template <typename T>
void MyClass::increment_helper (std::vector<T> v)
{ /* string from vector */ }
template <typename T>
void MyClass::increment_helper (T t)
{ /* no std::string and no std::vector */ }
template <typename T>
void MyClass::increment (std::string stats, T t)
{
/* common code */
increment_helper(t);
/* other common code */
}
答案 4 :(得分:0)
在c ++ 17中,您可以使用if constexpr
:
template <typename T>
void MyClass::increment(std::string stats, T tags)
{
if constexpr (std::is_same<std::string, T>::value)
{
//Perform some string manipulation
}
else if constexpr (std::is_same<std::vector<std::string>, T>::value)
{
//Extract each string from the vector
}
else
{
static_assert(false, "only strings or vectors are supported");
}
}
如果没有if constexpr
,如果使用该方法,则可能会在&#34; false branches&#34;中出现编译错误。因为代码应该对使用的类型有效。
在你的情况下,过载是最好的顺便说一句:
void MyClass::increment(std::string stats, const std::string& tags)
{
//Perform some string manipulation
}
void MyClass::increment(std::string stats, const std::vector<std::string>& tags)
{
//Extract each string from the vector
}