c++ - Typedef、模板和 const 关键字

标签 c++ templates constants typedef

我在使用带有 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();
}

我得到的唯一错误是在第二个指针声明上:

could not convert template argument ‘&Test::set’ to ‘void (Test::*)(int&)’ void (ptr2)(Test, const INTREF) = MethodCallerFactory::Method<&Test::set>::createMethodCaller();

似乎当我对引用类型使用 typedef 时,编译器忘记了 const 关键字。我不明白为什么会有问题。

最佳答案

我想纯文本替换让您误以为 const INTREF 会解析为 const int&(等同于 int const&),但是替换实际上解析为 int& const,其中 const 最终被忽略(这是唯一的情况,因为涉及 typedef,因为你不能显式声明 int& const 类型的变量)。所以你最终得到的是 int& 而不是 int const&

在代码中:

#include <type_traits>

typedef int& INTREF;

int main()
{
    static_assert(std::is_same<const INTREF, int&>{}, "!");
}

Live example

这就是为什么有些人(包括我)更喜欢采用 const-after 样式而不是 const-before 样式的原因之一(这两种样式在技术上是等价的): 除了更加一致,1 它允许通过执行直接的文本替换来理解编译器正在做什么。如果您编写的是 INTREF const 而不是 const INTREF,您可能会得出正确的结论。


1 您不能总是将 const 限定符放在它限定的类型之前,但您总是可以将它放在后面。例如,您可以将类型“指向常量整数的常量指针”拼写为 int const* const(其中 const 关键字始终应用于它之前的所有内容) , 但语法不允许这样写 const const int*; const int* const 是允许的,但它混合了 const-before 和 const-after,从而降低了一致性。

关于c++ - Typedef、模板和 const 关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30545972/

相关文章:

javascript - 使用 const 声明对象变量

c++ - 我是否应该将成员函数声明为 `const`,即使它修改了指针指向的内容?

c++ - 这个模板如何找到元组的索引?

C++ 互斥体和 const 正确性

C++ VS2010 判断是 Release 还是 Debug

c++ - 如何使用指针通过函数传递对象?

c++ - 模板如何导致 C++ 中的代码膨胀?

C++ 在编译时比较模板类型

scala - 在常量表达式中使用 scala 常量

c++ - Linux C++ 如何打开一个程序