【问题标题】:Friend function of templated structure with argument types depending on internals of the structure模板结构的友元函数,其参数类型取决于结构的内部结构
【发布时间】:2013-12-22 13:49:43
【问题描述】:

我想定义一个带有友元函数的模板结构,其参数类型派生自结构中定义的类型。如果对应的结构已经被实例化,友元函数应该可以在没有明确类型说明的情况下调用。

以下方法似乎有效:

template <typename T> struct A {
    typedef T const& underlying_param_type;
    typedef A<T>& param_type;
    friend void mutateA(param_type a, underlying_param_type b) { a.data_ = b; }
    T data_;
};

如果使用不依赖于结构内部的参数类型定义友元函数,则可以将接口和实现分开如下:

template <typename T> struct B;
template <typename T> void mutateB(B<T>& a, T const& b);

template <typename T> struct B {
    friend void mutateB <> (B<T>& a, T const& b);
    T data_;
};

template <typename T> void mutateB(B<T>& a, T const& b) { a.data_ = b; }

现在我想知道这两种方法是否可以结合使用。以下方法不起作用(clang++ 3.3、g++ 4.8.2、-std=c++11):

template <typename T> struct C;
template <typename T> void mutateC(typename C<T>::param_type a, typename C<T>::underlying_param_type b);

template <typename T> struct C {
    typedef T const& underlying_param_type;
    typedef C<T>& param_type;
    friend void mutateC <> (typename C<T>::param_type a, typename C<T>::underlying_param_type b);
    T data_;
};

template <typename T> void mutateC(typename C<T>::param_type a, typename C<T>::underlying_param_type b) { a.data_ = b; }

int main() {
    A<int> a;
    mutateA(a, 1);

    B<int> b;
    mutateB(b, 1);

    C<int> c; // error: no function template matches function template specialization 'mutateC'
    mutateC(c, 1);

    return 0;
}

我猜最后一种方法失败了,因为模板参数推导不适用于 ::。有什么想法吗?

【问题讨论】:

  • &lt;&gt; 变成 &lt;T&gt;?也许更多,但您的问题看起来像您的朋友声明中的语法错误。从一个更简单的朋友声明开始并让它发挥作用? (您与特定专业的朋友)
  • 将改为后声明C c;编译但 mutateC(c, 1) 不编译。 mutateC(c, 1) 在此设置中有效,但这对于我的用例来说还不够。
  • 啊,是的。对于任意typedef,您要求的内容需要反转图灵完整计算,因此是不可行的。提供更多细节,因为特殊情况可能是可行的。您的第一个有效的原因是 ADL 找到了 A&lt;T&gt; 参数的朋友,例如。在非 workimg 示例中传递的类型对 ADL 没有帮助,为此,您需要在所有类型上反转 template 替换。您编写的手动反转可以使用辅助函数来完成。
  • 最后一种方法失败是正确的,因为参数是不可推导的。你为什么要这样做? friend void mutateA(A&amp; a, const T&amp; b) { a.data_ = b; } 或者更好的 friend void mutateA(A&amp; a, T b) { a.data_ = std::move(b); } 有什么问题?
  • 在我的实际用例中,我有很多类似结构的友元函数。特别是,只有少数参数类型是从 T 派生的。派生规则将来可能会改变。引入 typedef 是为了使此类更改变得容易。我在工作解决方案(结构 A)中看到的唯一缺点是接口和实现没有分开。我想知道是否有办法将它们分开。如果这样的解决方案只是用一种丑陋换另一种,我可能会继续使用我所拥有的。无论如何,看看其他解决方案会很有趣。

标签: c++ templates struct friend-function


【解决方案1】:

做两个小改动:

  • friend void mutateC ...
  • mutateC(c, 1);

【讨论】:

  • 谢谢。 “如果对应的结构已经被实例化,友元函数应该可以在没有明确类型说明的情况下调用。”
【解决方案2】:

添加一个间接级别解决了这个问题:

template <typename T> struct C;
template <typename T> void mutateC_impl(typename C<T>::param_type a, typename C<T>::underlying_param_type b);

template <typename T> struct C {
    typedef T const& underlying_param_type;
    typedef C<T>& param_type;
    friend void mutateC(typename C<T>::param_type a, typename C<T>::underlying_param_type b) { mutateC_impl<T>(a, b); }
    friend void mutateC_impl<T>(typename C<T>::param_type a, typename C<T>::underlying_param_type b);
    private: T data_;
};

template <typename T> void mutateC_impl(typename C<T>::param_type a, typename C<T>::underlying_param_type b) { a.data_ = b; }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多