类模板实例化中的类型转换
Type conversion in class template instantiation
我有一个模板类item
,它存储各种类型的对象T
。它还在实例化/初始化中将属性附加到这些对象。
我想实现的一件特别的事情是,每当item
看到一个const char *
时,它就会将其视为std::string
并存储。可以这样做,如下所示。
但是在类型检查中,我发现从const char *
实例化的item
在类型上仍然与从std::string
实例化的item
不同。请参阅最后一行带有注释false
,我想将其true
。
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
template<typename T>
using bar = typename std::conditional<std::is_same<T, const char *>::value,
string, T>::type;
template<typename T>
class item
{
bar<T> thing;
// other attributes ...
public:
item(T t) : thing(t) {}
// other constructors ...
bar<T> what() const
{
return thing;
}
};
int main()
{
auto a = item("const char *"); // class template argument deduction (C++17)
auto b = item(string("string")); // class template argument deduction (C++17)
cout << std::boolalpha;
cout << (typeid(a.what()) == typeid(b.what())) << endl; // true
cout << (typeid(a) == typeid(b)) << endl; // false
}
我的问题是:是否可以对模板类item
进行任何更改,以便从const char *
实例化的item
在类型上与从std::string
实例化的item
相同?
换句话说,我可以对模板类item
的设计进行任何更改,以便typeid(a) == typeid(b)
的计算结果为 true 吗?
谢谢!
注意:这是之前关于模板功能的问题的后续。但我认为有一些本质上不同的东西,值得一个独立的问题。
编辑:我的目标是更改模板类item
的设计(例如item
签名(,而不是main
中的代码,假定由用户提供。我想让item
用户的生活更轻松,不要求他们在实例化中显式提供类型T
。这可以通过 C++17 模板类参数推导或一些等效的解决方法来完成。
更新:谢谢大家!特别感谢@xskxzr,他的一句话完全解决了我的问题。使用用于类模板参数推理的用户定义演绎指南,我甚至不需要以前的代码中的bar<T>
技术。我在下面放置了更新的代码供您比较。
#include <iostream>
#include <string>
using namespace std;
template<typename T>
class item
{
// UPDATE: no bar<T> needed any more
T thing;
// other attributes ...
public:
item(T t) : thing(t) {}
// other constructors ...
// UPDATE: no bar<T> needed any more
T what() const
{
return thing;
}
};
item(const char *) -> item<std::string>; // UPDATE: user-defined deduction guide !
int main()
{
auto a = item("const char *"); // class template argument deduction (C++17)
auto b = item(string("string")); // class template argument deduction (C++17)
cout << std::boolalpha;
cout << (typeid(a.what()) == typeid(b.what())) << endl; // true
cout << (typeid(a) == typeid(b)) << endl; // UPDATE: now true !
}
您可以添加用户定义的扣除指南:
item(const char *) -> item<std::string>;
有了这个演绎指南,a
将被推导出为item<std::string>
。
不可以,您不能直接使使用不同模板参数的两个模板化对象的 typeid 相同。
但是为了实现您的最终目标,您可以使用类似工厂的模式。它可能看起来像这样:
template<typename T, typename R = T>
item<R> make_item(T&& t)
{
return item<T>(std::forward<T>(t));
}
// Specialization for const char *
template<>
item<std::string> make_item(const char *&& str)
{
return item<std::string>(str);
}
这种方法的缺点是,您需要使用此工厂构造所有对象。如果你有很多例外,你需要为每个例外进行专业化。
这与其说是答案,不如说是猜测,但我会说不。 模板在编译时展开,因此因为您正在创建一个
item<const char*>
和一个
item<std::string>
然后扩展的代码看起来像
class item1
{
bar<const char*> thing;
// other attributes ...
public:
item(const char* t) : thing(t) {}
// other constructors ...
bar<const char*> what() const
{
return thing;
}
};
class item2
{
bar<std::string> thing;
// other attributes ...
public:
item(std::string t) : thing(t) {}
// other constructors ...
bar<std::string> what() const
{
return thing;
}
};
(或多或少;它们实际上不会被称为item1和item2(
您选择如何评估这两种类型取决于您,但对于编译器来说,它们实际上是两种不同的类型。
好吧,我以前从未见过或使用 std::condition,所以我不确定它在做什么,但在阅读它并玩弄你的代码后,我确实通过使用它让它"工作">
bar<T>
作为模板类型。 所以而不是
auto a = item<const char*>("const char *");
auto b = item<string>(string("string"));
我做了
auto a = item<bar<const char*>>("const char *");
auto b = item<bar<string>>(string("string"));
问题是在这两种情况下,您需要模板类型相同,这意味着在扩展模板之前,类型需要解析为 std::string。 只要使用条件,就可以定义任何类型。
auto c = item<bar<int>>(5);
不确定这是一个很好的解决方案(这就是为什么我说"工作"(,但看看我关于类类型实际上不同的另一个答案。
- 检查某些类型是否是模板类 std::optional 的实例化
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 将显式实例化的函数模板与转换匹配
- 实例化模板时,我是否必须显式显示参数包中的类型?
- 无法将模板子类强制转换为其他模板实例化
- 在实例化之前推断函数模板的返回类型
- 使用用户定义的类型 UDT 实例化 std::atomic<>。如果 UDT 具有虚函数,则 l 墨水将失败。为什么?
- 类模板实例化中的类型转换
- 引用的静态强制转换强制模板实例化,其中不完整的类型很好
- 有没有办法将一对元组剥离为可变参数模板类型或实例化具有可变参数类型的东西?
- 如何在尝试为某些非类型值实例化模板子类方法时产生编译器错误
- 使用标准类型的动态类型信息实例化标识符
- 纯抽象类和派生类型的实例化
- 模板类型名实例化错误
- 使用bool非类型参数实例化类模板时出错
- 在没有数据重复的情况下强制转换/实例化/转换为子类/超类
- std::conditional 的可变模板化使用,其中一种类型是实例化失败
- 模板化操作符实例化和类型转换
- "*"标记之前的预期构造函数、析构函数或类型转换 模板化链表
- 如何从另一个实例的类型动态实例化新实例?C++