【问题标题】:XCODE 4.6 C++ template function with function pointer as a parameter in template classXCODE 4.6 C++模板函数,函数指针作为模板类中的参数
【发布时间】:2013-04-20 21:46:39
【问题描述】:

我已经为此苦苦挣扎了大约半天,似乎至少 XCode 4.6 有一个错误,即模板类的某些声明会违反语言并允许将 const 数据从类内传递到带参数的外部函数没有 const 修饰符。

下面的示例将编译,即使是艰难的模板声明 Tcaller::call() 方法指定作为引用传递的 const 参数 但是静态 cmp 函数提供了无用的 *const & 修饰符。

template< typename T> struct Tcalled
{
    // !!!error - this prototype doesn't protect the data passed to function
    // because it should be declared with const modifiers but it wouldn't compile then.
    // SEE: Below my NOTE for correct function prototype.
        static bool cmp(const Tcalled*& item, const int& key) //<- correct but doesn't work
        static bool cmp(Tcalled* const & item, const int& key) //<- invalid but works!!
        {
            return (item->index = key); /// error - we modify const object here !
        }

    T index;
};

template < typename T> struct Tcaller
{
    Tcaller(){}

    template < typename K, bool (*compare)(const T& item, const K& key) >
    bool call(int k) const { return compare(data, k); }

    T       data;

};


int main(int argc, char *argv[])
{
    const Tcaller<Tcalled<int>* > tmp;  // <- const data
    int k = 1;

    tmp.call<int,Tcalled<int>::cmp>(k);  //call here WILL modify const data !!

}

还有一个问题:我如何强制 XCode 遵守规则并允许我进行原型设计 我为模板参数声明的静态函数?至于现在,这些是我在正确声明静态方法时得到的 XCode 错误:

调用“call”没有匹配的成员函数 候选模板被忽略:模板参数“比较”的显式指定参数无效

谢谢!

【问题讨论】:

  • const Tcalled* 是指向 const Tcall 的指针,Tcalled* const 是指向 Tcall 的 const 指针。它们是不同的东西

标签: c++ xcode templates pointers arguments


【解决方案1】:

大概你的意思是当参数被声明为Tcalled&lt;T&gt;* const &amp; item 并且cmp 的主体应该使用== 而不是= 时它可以工作。

您对模板参数的实例化方式存在误解。这不仅仅是模板参数的复制粘贴替换。您期望 const T&amp; 在使用 T 实例化为 Tcalled&lt;int&gt;* 时将等效于 const Tcalled&lt;int&gt;*&amp;;即“对指向 const Tcalled&lt;int&gt; 的指针的引用。

但是,这是错误的,const 适用于整个 T 类型。所以真的,在实例化之后,const T&amp; 等价于Tcalled&lt;int&gt;* const&amp;。这就是为什么将参数声明为 Tcalled* const &amp; item 可以正常工作的原因。

要使其与const Tcalled&lt;T&gt;*&amp; item 的声明一起使用,必须进行一些更改:

  1. call 函数模板参数应该这样定义:

    template < int (*compare)(T& item) >
    

    也就是说,函数指针类型采用T&amp;,而不是const T&amp;。这是有道理的,因为cmp 函数根本不引用const 对象(它引用非const 指针)。

  2. call 函数不应该是const

    int call() { return compare(data); }
    

    这是因为它传递了它的成员T 进行比较,这是对非const 对象的引用(指针本身不是const)。如果它是const 函数,它就不能这样做,因为它不能保证compare 不会修改对象。

  3. Tcaller 必须用T 实例化为const Tcalled&lt;int&gt;*

    Tcaller<const Tcalled<int>* > tmp;
    

【讨论】:

  • 感谢您抽出宝贵时间回答。我发现了这一点,但编译器仍然允许实际修改 const 对象 - 请参阅上面的更新代码。我不应该依赖编译器的消息或警告吗?另外-仍然是有效的问题-如何以正确的方式在外部静态函数中保留“常量”来声明类似于上述内容?
  • 老实说,我害怕这种解决方案!我最初是这样做的,但这迫使我在模板中只有 const 数据 - 因为这只是一个虚拟示例,它可能看起来是一个很好的解决方案,但在实际代码中,我会坚持使用 const 数据类型作为模板参数,这是不可接受的这是非常量数据的容器类..困惑:S
  • @seeoneself data 成员不是 const。这是一个指向const 对象的非const 指针。
  • @seeoneself 请阅读Why am I getting an error converting a Foo**Foo const**?。唯一的区别是您使用Foo* 初始化Foo const*&amp;,但推理是相同的。
  • 好的,我想我确认这不是我需要的解决方案。我确实应用了所有修改并明确指定 const Tcall* 作为模板参数,但我最终将可分配指针存储在 Tcaller 中,但无法通过指针访问存储的数据(例如,无法访问数据->索引= 0 在 call() 方法中,因为它们是 const)。有什么解决方案吗?我想要的是拥有一个非常量对象的容器,但是当作为对静态方法的引用传递时,可以将它们声明为 const。很抱歉延长了这个时间,但真的很想知道。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 2021-12-10
  • 1970-01-01
相关资源
最近更新 更多