首页 文章

函数签名式表达式作为C模板参数

提问于
浏览
52

我正在看Don Clugston的FastDelegate迷你库,并注意到一个奇怪的语法技巧,具有以下结构:

TemplateClass< void( int, int ) > Object;

几乎看起来好像函数签名被用作模板实例声明的参数 .

这种技术(其在FastDelegate中的存在显然是由于一个Jody Hagins)被用于简化模板实例的声明,其具有半任意数量的模板参数 .

也就是说,它允许这样的事情如下:

// A template with one parameter
template<typename _T1>
struct Object1
{
    _T1 m_member1;
};

// A template with two parameters
template<typename _T1, typename _T2>
struct Object2
{
    _T1 m_member1;
    _T2 m_member2;
};

// A forward declaration
template<typename _Signature>
struct Object;

// Some derived types using "function signature"-style template parameters
template<typename _Dummy, typename _T1>
struct Object<_Dummy(_T1)> : public Object1<_T1> {};

template<typename _Dummy, typename _T1, typename _T2>
struct Object<_Dummy(_T1, _T2)> : public Object2<_T1, _T2> {};

// A. "Vanilla" object declarations
Object1<int> IntObjectA;
Object2<int, char> IntCharObjectA;

// B. Nifty, but equivalent, object declarations
typedef void UnusedType;
Object< UnusedType(int) > IntObjectB;
Object< UnusedType(int, char) > IntCharObjectB;

// C. Even niftier, and still equivalent, object declarations
#define DeclareObject( ... ) Object< UnusedType( __VA_ARGS__ ) >
DeclareObject( int ) IntObjectC;
DeclareObject( int, char ) IntCharObjectC;

尽管存在真正的黑客味,但我发现这种对可变参数模板参数的欺骗性仿真非常令人兴奋 .

这个技巧的真正原因似乎是我可以将像“Type1(Type2,Type3)”这样的文本结构作为模板的参数传递 . 所以这是我的问题:编译器究竟如何解释这个结构?它是功能签名吗?或者,它只是一个带括号的文本模式吗?如果是前者,那么这是否意味着就模板处理器而言,任何任意函数签名都是有效类型?

一个后续问题是,由于上面的代码示例是有效的代码,为什么C标准不允许你做类似下面的事情,它不能编译?

template<typename _T1>
struct Object
{
    _T1 m_member1;
};

// Note the class identifier is also "Object"
template<typename _T1, typename _T2>
struct Object
{
    _T1 m_member1;
    _T2 m_member2;
};

Object<int> IntObject;
Object<int, char> IntCharObject;

2 回答

  • 4

    关于你的第一个问题 - 关于类型 int(char, float) - 这是一个有效的C类型,是一个函数的类型,它接收 charfloat 并返回 int . 请注意,这是实际函数的类型,而不是函数指针,它将是 int (*) (char, float) . 任何函数的实际类型都是这种不寻常的类型 . 例如,类型

    void DoSomething() {
        /* ... */
    }
    

    void () .

    在常规编程期间没有出现太多的原因是在大多数情况下你不能声明这种类型的变量 . 例如,此代码是非法的:

    void MyFunction() { 
        void function() = DoSomething; // Error!
    }
    

    但是,实际上看到使用的函数类型的一种情况是传递函数指针:

    void MyFunction(void FunctionArgument()) {
         /* ... */
    }
    

    更常见的是看到这种函数被写入函数指针,但是接受函数本身是完全正常的 . 它在幕后得到了 .

    至于你的第二个问题,为什么使用不同数量的参数编写相同的模板是非法的,我不知道禁止它的规范中的确切措辞,但它与你曾经的事实有关声明了一个类模板,你不能改变它的参数个数 . 但是,您可以对具有不同数量的参数的模板提供部分特化,当然,前提是部分特化仅专用于原始参数数量 . 例如:

    template <typename T> class Function;
    template <typename Arg, typename Ret> class Function<Ret (Arg)> { 
        /* ... */
    };
    

    这里, Function 总是带一个参数 . 模板特化需要两个参数,但特化仍然只有一种类型(特别是 Ret (Arg) ) .

  • 42
    int* int_pointer;    // int_pointer   has type "int*"
    int& int_reference;  // int_reference has type "int&"
    int  int_value;      // int_value     has type "int"
    
    void (*function_pointer)(int, int);    // function_pointer has type
                                           // "void (*)(int, int)"
    void (&function_reference)(int, int);  // function_reference has type
                                           // "void (&)(int ,int)"
    void function(int, int);               // function has type
                                           // "void(int, int)"
    
    template<>
    struct Object1<void(int, int)>
    {
        void m_member1(int, int);  // wait, what?? not a value you can initialize.
    };
    

相关问题