Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板结构的友元函数,其参数类型取决于结构的内部结构_C++_Templates_Struct_Friend Function - Fatal编程技术网

C++ 模板结构的友元函数,其参数类型取决于结构的内部结构

C++ 模板结构的友元函数,其参数类型取决于结构的内部结构,c++,templates,struct,friend-function,C++,Templates,Struct,Friend Function,我想用友元函数定义一个模板结构,友元函数的参数类型派生自结构中定义的类型。如果相应的结构已经实例化,那么friend函数应该可以在没有显式类型规范的情况下调用 以下方法似乎有效: template <typename T> struct A { typedef T const& underlying_param_type; typedef A<T>& param_type; friend void mutateA(param_typ

我想用友元函数定义一个模板结构,友元函数的参数类型派生自结构中定义的类型。如果相应的结构已经实例化,那么friend函数应该可以在没有显式类型规范的情况下调用

以下方法似乎有效:

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_;
};
模板结构A{
typedef T const&底层参数类型;
类型定义A和参数类型;
friend void mutateA(参数类型a,基础参数类型b){a.data}=b;}
T数据;
};
如果使用不依赖于结构内部的参数类型定义friend函数,则可以按如下方式分离接口和实现:

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; }
模板结构B;
模板B(B&a、T&B);
模板结构B{
朋友B(B&a、T&B);
T数据;
};
模板B(B&a,T常数&B){a.data}
现在我想知道这两种方法是否可以结合起来。以下方法不起作用(clang++3.3,g++4.8.2,-std=c++11):

模板结构C;
模板void mutateC(类型名C::参数类型a,类型名C::基础参数类型b);
模板结构C{
typedef T const&底层参数类型;
类型定义C和参数类型;
friend void mutateC(类型名C::参数类型a,类型名C::基础参数类型b);
T数据;
};
模板void mutateC(类型名C::参数类型a,类型名C::基础参数类型b){a.data=b;}
int main(){
A A;
突变(a,1);
B B;
b(b,1);
C C;//错误:没有与函数模板专用化“mutateC”匹配的函数模板
mutateC(c,1);
返回0;
}

我猜最后一种方法失败了,因为模板参数推断在以下情况下不起作用:。有什么想法吗?

做两个小改动:

  • 朋友空变
  • 突变c(c,1)
添加一个间接级别可以解决问题:

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; }
模板结构C;
模板void mutateC_impl(类型名C::参数类型a,类型名C::基础参数类型b);
模板结构C{
typedef T const&底层参数类型;
类型定义C和参数类型;
friend void mutateC(类型名C::参数类型a,类型名C::基础参数类型b){mutateC_impl(a,b);}
friend void mutateC_impl(类型名C::参数类型a,类型名C::基础参数类型b);
私有:T数据;
};
模板void mutateC_impl(类型名C::参数类型a,类型名C::基础参数类型b){a.data=b;}

谢谢。“如果相应的结构已实例化,则friend函数应该可以在没有显式类型规范的情况下调用。”
?可能更多,但您的问题看起来像您的好友声明中的语法错误。从一个简单的朋友声明开始,然后让它开始工作?(如果您是某一特定专业的朋友)在更改为语句C之后;编译,但mutateC(c,1)不编译。mutateC(c,1)在这种设置下工作,但这对于我的用例来说是不够的。啊,是的。对于任意的
typedef
来说,您所要求的需要反转图灵完整计算,因此是不可行的。提供更多细节,因为特殊情况可能是可行的。第一个参数有效的原因是ADL找到了
A
参数的朋友,例如。非工作示例中传递的类型对ADL没有帮助,要做到这一点,您需要在所有类型上反转
模板
替换。您编写的手动反转可以使用辅助函数来实现这一点。您正确地认为,最后一种方法失败,因为参数是不可推断的。你为什么要这样做?
friend void mutateA(A&A,const T&b){A.data_=b;}
或者更好的是,
friend void mutateA(A&A,tb){A.data_=std::move(b)}
在我的实际用例中,我有许多类似结构的friend函数。特别是,只有少数参数类型是从T派生的。派生规则将来可能会更改。typedef的引入是为了使这些更改变得容易。我在工作解决方案(struct A)中看到的唯一缺点是接口和实现没有分开。我想知道是否有办法把它们分开。如果这样的解决方案只是用一个丑陋换另一个丑陋,我可能会继续用我现有的东西。在任何情况下,看到其他解决方案都会很有趣。
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; }