如何解决模板参数推导中的常量/非常量冲突
How to resolve const/non-const conflict in template argument deduction
我有一个函数模板,它接受一个std::pair
以及这对类型之一的值。我想使用std::map
中的一个条目作为对参数来调用此函数。
#include <map>
#include <utility>
template <typename T1, typename T2>
void do_stuff(std::pair<T1, T2> const &pair, T1 const &val) {
// Imagine that this does something important...
}
int main() {
std::map<int, float> foo { { 0, 0.0 } };
do_stuff(*foo.begin(), 0);
}
由于映射项的类型为std::pair<const int, float>
,因此无法编译,因此T1
的类型推导具有冲突类型:const int
通过pair
参数,int
通过val
参数。
test.cc: In function ‘int main()’:
test.cc:12:27: error: no matching function for call to ‘do_stuff(std::pair<const int, float>&, int)’
do_stuff(*foo.begin(), 0);
^
test.cc:5:6: note: candidate: template<class T1, class T2> void do_stuff(const std::pair<_T1, _T2>&, const T1&)
void do_stuff(std::pair<T1, T2> const &pair, T1 const &val) {
^~~~~~~~
test.cc:5:6: note: template argument deduction/substitution failed:
test.cc:12:27: note: deduced conflicting types for parameter ‘const T1’ (‘const int’ and ‘int’)
do_stuff(*foo.begin(), 0);
^
解决这场冲突的最佳方法是什么?理想情况下,我希望T1
被推导为int
,但如果实现起来更简单,那么它可以是const int
。
我发现我可以通过在val
参数的类型上使用std::remove_const
或std::decay
来解决错误:
void do_stuff(std::pair<T1, T2> const &pair, typename std::remove_const<T1>::type const &val) {
但我不知道其中哪一个更合适,或者是否有其他更好的解决方案。
一种解决方案是使用std::add_const
,而不是直接使用关键字const
。
通过模板的往返防止通过以下参数类型进行类型推导:
#include <map>
#include <type_traits>
#include <utility>
template< class T1, class T2 >
void do_stuff( std::pair<T1, T2> const& pair, std::add_const_t<T1>& val )
{
// Imagine that this does something important...
(void) pair; (void) val;
}
auto main()
-> int
{
std::map<int, float> foo { { 0, 0.0f } };
do_stuff(*foo.begin(), 0);
}
template<class T>struct identity{using type=T;};
template<class T>using no_deduce=typename identity<T>::type;
在no_deduce
中包装第二种类型以阻止推导。
template <typename T1, typename T2>
void do_stuff(std::pair<T1, T2> const &pair, no_deduce<T1> const &val) {
// Imagine that this does something important...
}
这两者都有效,并且很清楚你为什么要这么做。
现在,如果T1
是引用类型,那么您想做什么,以及const&
在这种情况下会做什么,这可能值得考虑。假设T1
是int&
,那么int& const&
就变成了int&
。
这可能不是你想要的。
也许你想要的,你真正想要的,是:
template <typename T1, typename T2>
void do_stuff(std::pair<T1, T2> const &pair, std::remove_reference_t<T1> const &val) {
// Imagine that this does something important...
}
如果你想要一个const&
,你必须忘记你的&
,如果你想防止val
被修改,你最好确保它是const
。现在,不要浪费你宝贵的const&
,remove_reference_t
,一切都会好起来的。
如果你想处理volatile
,你必须处理remove_volatile_t
。用template<class T>using clean_t=std::remove_cv_t<remove_reference_t<T>>
把它们永远绑在一起。如果你想要const&
,你必须去
template <typename T1, typename T2>
void do_stuff(std::pair<T1, T2> const &pair, clean_t<T1> const &val) {
// Imagine that this does something important...
}
简单地说const&
很容易,但事实就是这样。
不是很优雅,但我想您可以在两个不同的模板参数中分离T1
。
类似的东西
template <typename T1, typename T2, typename T3>
void do_stuff(std::pair<T1, T2> const &pair, T3 const &val) {
// Imagine that this does something important...
}
您可以通过std::enable_if_t
添加一个检查,以在T1
和T3
之间施加相关性;例如
template <typename T1, typename T2, typename T3,
typename = std::enable_if_t<std::is_same<std::remove_const_t<T1>, std::remove_const_t<T3>>::value>>
void do_stuff(std::pair<T1, T2> const &pair, T3 const & val) {
// Imagine that this does something important...
}
- #定义c-预处理器常量..我做错了什么
- 用C++中的一个变量定义一个常量
- 什么时候在C++中返回常量引用是个好主意
- 代理对象的常量正确性
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 通过多个头文件使用常量变量
- 写入位置0x0000000C时发生访问冲突
- 在cuda线程之间共享大量常量数据
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 是默认情况下分配给char数组常量的值
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- 私有类型的静态常量成员
- 类似枚举的计算常量
- 传递指向常量指针的指针到字节数组的语义冲突
- 忽略候选模板:推断参数的冲突类型:<常量 T &> 与 <T &>
- 如何解决模板参数推导中的常量/非常量冲突
- 避免预定义的数字常量与c++中的枚举冲突
- C++错误:推断出参数'T'字符串与常量字符的冲突类型 *