我的代码在这里:
#include <iostream>
#include <memory>
#include <queue>
template<typename TValue>
[[maybe_unused]]
constexpr auto t1(const std::queue<TValue> &value) -> void {
std::queue<TValue> temp = value;
while (!temp.empty()) {
std::cout << temp.front() << std::endl;
temp.pop();
}
}
template<typename TValue>
constexpr auto t1(const TValue &nm) -> void {
std::cout << nm << std::endl;
}
template<typename TValue>
constexpr auto t1(const std::shared_ptr<TValue> &nm) -> void {
t1<TValue>(*nm);
}
int main(int argc, char **argv) {
std::shared_ptr<const int> s_ptr = std::make_shared<const int>(7);
t1(s_ptr);
return 0;
}
字符串
此代码无法编译(https://godbolt.org/z/crvKb7rEz):
错误C2338:static_assert失败:'C++标准禁止const元素的容器,因为分配器格式不正确。'
我试着用shared_ptr
修改模板,如下所示:
template<typename TValue>
constexpr auto t1(const std::shared_ptr<TValue> &nm) -> void {
const int temp = *nm;
t1<TValue>(temp);
}
型
它会导致同样的错误。我还尝试获取'TValue'类型:
template<typename TValue>
constexpr auto t1(const std::shared_ptr<TValue> &nm) -> void {
if constexpr (std::is_same_v<TValue, const int>){
static_assert(false, "??");
}
t1<TValue>(*nm);
}
型static_assert
被触发。这意味着'TValue'是'const std::string'。
不小心,我删除了<TValue>
这样:
template<typename TValue>
constexpr auto t1(const std::shared_ptr<TValue> &nm) -> void {
t1(*nm);
}
型
或者:
template<typename TValue>
constexpr auto t1(const std::shared_ptr<TValue> &nm) -> void {
t1<std::remove_cv_t<TValue>>(*nm);
}
型
还有:
template<typename TValue>
constexpr auto t1(const TValue &nm) -> void {
std::cout << nm << std::endl;
}
template<typename TValue>
constexpr auto t1(const std::shared_ptr<TValue> &nm) -> void {
t1<TValue>(*nm);
}
int main(int argc, char **argv) {
std::shared_ptr<const int> s_ptr = std::make_shared<const int>(7);
t1(s_ptr);
return 0;
}
型
所有这些工作。
为什么模板要使用std::queue
重载时,<TValue>
euqal到const int
?我除了它使用:
template<typename TValue>
constexpr auto t1(const TValue &nm) -> void {
std::cout << nm << std::endl;
}
型
1条答案
按热度按时间zysjyyx41#
问题是你显式地提供了模板参数
TValue
,这导致了std::deque<const std::string>
的示例化。std::deque<T>
需要一个非常量、非易失性的T
,正如失败的静态Assert所说:错误:static assertion failed:
std::deque
must have a non-const,non-volatilevalue_type
最小可复制示例
为了说明发生了什么,这里有一个简化版本的问题(https://godbolt.org/z/zYPhhb5dq):
个字符
溶液
你可以写
t1(*nm)
。这里的区别是std::deque<const std::string>
从来没有示例化过。相反,替换到t1(std::deque)
会失败,因为*nm
是const std::string
,而std::deque<TValue>
中的TValue
不能从const std::string
推导出来。型
t1<std::remove_cv_t<TValue>>(*nm);
也可以工作(尽管你不应该写它),因为你示例化了std::deque<std::string>
。这是有效的,但是,重载解析将选择t1(const T&)
,因为没有从std::string
到std::deque
的隐式转换。**你应该写
t1(*nm);
**通常最好推导模板参数,而不是显式提供它们。SFINAE友好性说明
潜在的问题是
static_assert
不是SFINAE友好的,也就是说,它会导致 * 后 * 替换的错误。在C++20中,可以使用约束代替static_assert
,同时具有相同的模板参数:型
如果这样做,
foo<const int>(0)
是有效的(https://godbolt.org/z/TWKxs99Yj)。我不认为
std::deque
有这样的约束是法律的,如果有,你的代码就可以工作了。