我在使用带有const关键字的模板时遇到问题(对于函数参数类型),为了说明我创建了一个很小的代码:
template <typename ClassType, typename ReturnType, typename ... Args>
struct MethodCallerFactory
{
typedef ReturnType (*Type)(ClassType*, Args...);
template <ReturnType (ClassType::*Pointer)(Args...)>
struct Method
{
static Type createMethodCaller()
{
ReturnType (*caller)(ClassType*, Args...) = [](ClassType* obj, Args ... args) -> ReturnType
{
ReturnType (ClassType::*ptr)(Args...) = Pointer;
return (obj->*ptr)(args...);
};
return caller;
}
};
};
class Test
{
public :
void set(const int& p)
{
n = p;
}
void set2(int p)
{
n = p;
}
void set3(const int p)
{
n = p;
}
void set4(int& p)
{
n = p;
}
private :
int n;
};
typedef int& INTREF;
typedef int INTVALUE;
int main()
{
void (*ptr1)(Test*, const int&) = MethodCallerFactory<Test, void, const int&>::Method<&Test::set>::createMethodCaller();
void (*ptr2)(Test*, const INTREF) = MethodCallerFactory<Test, void, const INTREF>::Method<&Test::set>::createMethodCaller();
void (*ptr3)(Test*, int) = MethodCallerFactory<Test, void, int>::Method<&Test::set2>::createMethodCaller();
void (*ptr4)(Test*, INTVALUE) = MethodCallerFactory<Test, void, INTVALUE>::Method<&Test::set2>::createMethodCaller();
void (*ptr5)(Test*, int) = MethodCallerFactory<Test, void, const int>::Method<&Test::set3>::createMethodCaller();
void (*ptr6)(Test*, const INTVALUE) = MethodCallerFactory<Test, void, const INTVALUE>::Method<&Test::set3>::createMethodCaller();
void (*ptr7)(Test*, int&) = MethodCallerFactory<Test, void, int&>::Method<&Test::set4>::createMethodCaller();
void (*ptr8)(Test*, INTREF) = MethodCallerFactory<Test, void, INTREF>::Method<&Test::set4>::createMethodCaller();
}
我得到的唯一错误是第二个指针声明:
无法将模板参数'&amp; Test :: set'转换为'void(Test :: *)(int&amp;)' void( ptr2)(Test ,const INTREF)= MethodCallerFactory :: Method&lt;&amp; Test :: set&gt; :: createMethodCaller();
似乎当我使用带引用类型的typedef时,编译器会忘记const关键字。我不明白为什么会有这个问题。
答案 0 :(得分:6)
我认为纯文本替换会让您误以为const INTREF
会解析为const int&
(相当于int const&
),但替换实际上会解析为int& const
,其中{最终会忽略{1}}(这只是因为涉及const
,因为您无法明确声明类型为typedef
的变量)。所以你最终得到的是int& const
而不是int&
。
在代码中:
int const&
这是为什么有些人(包括我)更喜欢采用#include <type_traits>
typedef int& INTREF;
int main()
{
static_assert(std::is_same<const INTREF, int&>{}, "!");
}
- 之后风格超过const
- 之前的风格(两种风格在技术上等同)的原因之一:除了更多一致, 1 它允许通过执行简单的文本替换来理解编译器正在做什么。如果你写了const
而不是INTREF const
,你可能会得出正确的结论。
1 您不能始终将const INTREF
限定符放在它符合条件的类型之前,但您可以随时将它放在后面。例如,你可以拼出类型&#34;常量指针到一个常数整数&#34; as const
(其中int const* const
关键字始终适用于之前的所有内容),但语法不允许编写const
;允许使用const const int*
,但它会混合const int* const
- 之前和const
- 之后,从而降低一致性。