C++ 匹配参数的好友模板函数实例化

C++ 匹配参数的好友模板函数实例化,c++,templates,instantiation,friend,C++,Templates,Instantiation,Friend,我有一个模板类,它应该有一个朋友:一个make_object函数,允许扣除某些类型和值。我只希望与那些与模板类类型匹配的实例化交朋友。我的代码的简化版本如下: template<size_t S, typename T> class Object { private: Object(T t); template<typename U, typename... Args> friend auto make_object(U, Args... arg

我有一个模板类,它应该有一个朋友:一个
make_object
函数,允许扣除某些类型和值。我只希望与那些与模板类类型匹配的实例化交朋友。我的代码的简化版本如下:

template<size_t S, typename T>
class Object {
private:
    Object(T t);

    template<typename U, typename... Args>
    friend auto make_object(U, Args... args);
};


template<typename U, typename... Args>
inline auto make_object(U u, Args... args)
{
    constexpr size_t S = sizeof...(Args);
    return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
}
模板
类对象{
私人:
对象(T);
模板
朋友自动生成对象(U,Args…Args);
};
模板
内联自动生成对象(U,参数…参数)
{
constexpr size\u t S=sizeof…(Args);
返回std::unique_ptr(新对象(u));
}

以这段代码为例,我希望只交那些
make\U object
的实例化的朋友,它们的
typename U
与对象的
typename T
匹配。这可能吗?

如果您的需求只是使用与
T
相同的模板参数与函数模板交朋友,那么这就足够了:

#包括
模板
自动生成对象(T、TArgs…);
模板
类对象{
私人:
对象(T);
朋友自动生成对象(T);
};
模板
自动生成对象(T、TArgs…args){
对象{t};//编译
}
模板
自动生成对象(浮动f){
//错误:构造函数是私有的
对象{static_cast(f)};
}

如果您的需求只是使用与
T
相同的模板参数与函数模板交朋友,那么这就足够了:

#包括
模板
自动生成对象(T、TArgs…);
模板
类对象{
私人:
对象(T);
朋友自动生成对象(T);
};
模板
自动生成对象(T、TArgs…args){
对象{t};//编译
}
模板
自动生成对象(浮动f){
//错误:构造函数是私有的
对象{static_cast(f)};
}

您可以使用类将
make\U object
U
参数(必须与
object
T
相匹配)与
参数包(不必匹配)分开。然后,与helper类交朋友,让函数的所有实例化都可以访问
对象的
私有成员

template<typename U>
struct make_object_t;

template<std::size_t S, typename T>
class Object {
private:
    Object(T t);

    friend class make_object_t<T>;
};

template<typename U>
struct make_object_t {
    template<typename... Args>
    static auto make_object(U u, Args... args) {
        constexpr std::size_t S = sizeof...(Args);
        return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
    }
};
模板
结构生成对象;
模板
类对象{
私人:
对象(T);
friend类生成对象;
};
模板
结构生成对象{
模板
静态自动生成对象(U、Args…Args){
constexpr std::size\u t S=sizeof…(Args);
返回std::unique_ptr(新对象(u));
}
};
最后,编写一个helper函数来隐藏API中的类:

template<typename U, typename... Args>
auto make_object(U&& u, Args&&... args) {
    return make_object_t<U>::template make_object<Args...>(std::forward<U>(u), std::forward<Args>(args)...);
}
模板
自动生成对象(U&&U,参数&&…参数){
返回make_object_t::模板make_object(std::forward(u)、std::forward(args)…);
}
现在,例如,这是有效的

int main() {
    std::unique_ptr<Object<3, int>> ptr = make_object(5, 'a', 0x0B, "c");
}
intmain(){
std::unique_ptr ptr=make_对象(5,'a',0x0B,“c”);
}
但是,例如,
make\u object\t
不能使用
object::object

template<>
struct make_object_t<char> {
    template<typename... Args>
    static auto make_object(char u, Args... args) {
        constexpr std::size_t S = sizeof...(Args);
        return std::unique_ptr<Object<S, int>>(new Object<S, int>(u));
    }
};
int main() {
    // error here from instantiation of above function template
    auto oops = make_object('n', 'o');
}
template<size_t, typename>
class Object;

template<size_t S, typename T>
inline auto create_object(T t) {
   return std::unique_ptr<Object<S, T>>(new Object<S, T>(t));
}

template<size_t S, typename T>
class Object {
private:
    Object(T t);
    friend auto create_object<S, T>(T);
};
template<typename U, typename... Args>
inline auto make_object(U u, Args... args)
{
    constexpr size_t S = sizeof...(Args);
    return create_object<S, U>(std::move(u));
}
模板
结构生成对象{
模板
静态自动生成对象(字符u、参数…参数){
constexpr std::size\u t S=sizeof…(Args);
返回std::unique_ptr(新对象(u));
}
};
int main(){
//上述函数模板的实例化在此处出错
自动oops=生成对象('n','o');
}

您可以使用类将
make\U object
U
参数(必须与
object
T
匹配)从
参数包中分离出来,该参数包不必匹配。然后,与helper类交朋友,让函数的所有实例化都可以访问
对象的
私有成员

template<typename U>
struct make_object_t;

template<std::size_t S, typename T>
class Object {
private:
    Object(T t);

    friend class make_object_t<T>;
};

template<typename U>
struct make_object_t {
    template<typename... Args>
    static auto make_object(U u, Args... args) {
        constexpr std::size_t S = sizeof...(Args);
        return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
    }
};
模板
结构生成对象;
模板
类对象{
私人:
对象(T);
friend类生成对象;
};
模板
结构生成对象{
模板
静态自动生成对象(U、Args…Args){
constexpr std::size\u t S=sizeof…(Args);
返回std::unique_ptr(新对象(u));
}
};
最后,编写一个helper函数来隐藏API中的类:

template<typename U, typename... Args>
auto make_object(U&& u, Args&&... args) {
    return make_object_t<U>::template make_object<Args...>(std::forward<U>(u), std::forward<Args>(args)...);
}
模板
自动生成对象(U&&U,参数&&…参数){
返回make_object_t::模板make_object(std::forward(u)、std::forward(args)…);
}
现在,例如,这是有效的

int main() {
    std::unique_ptr<Object<3, int>> ptr = make_object(5, 'a', 0x0B, "c");
}
intmain(){
std::unique_ptr ptr=make_对象(5,'a',0x0B,“c”);
}
但是,例如,
make\u object\t
不能使用
object::object

template<>
struct make_object_t<char> {
    template<typename... Args>
    static auto make_object(char u, Args... args) {
        constexpr std::size_t S = sizeof...(Args);
        return std::unique_ptr<Object<S, int>>(new Object<S, int>(u));
    }
};
int main() {
    // error here from instantiation of above function template
    auto oops = make_object('n', 'o');
}
template<size_t, typename>
class Object;

template<size_t S, typename T>
inline auto create_object(T t) {
   return std::unique_ptr<Object<S, T>>(new Object<S, T>(t));
}

template<size_t S, typename T>
class Object {
private:
    Object(T t);
    friend auto create_object<S, T>(T);
};
template<typename U, typename... Args>
inline auto make_object(U u, Args... args)
{
    constexpr size_t S = sizeof...(Args);
    return create_object<S, U>(std::move(u));
}
模板
结构生成对象{
模板
静态自动生成对象(字符u、参数…参数){
constexpr std::size\u t S=sizeof…(Args);
返回std::unique_ptr(新对象(u));
}
};
int main(){
//上述函数模板的实例化在此处出错
自动oops=生成对象('n','o');
}

如果你想拥有一个好友模板,你可以像你的例子一样,将该模板的所有安装都设置为好友,也可以将完全专业化设置为好友

#include <type_traits>
#include <iostream>
#include <memory>

template<typename U>
struct object_maker;

template<std::size_t S, typename T>
class Object {
private:
    Object(T) {}

    friend struct object_maker<T>;
};


template<typename U>
struct object_maker
{
    template<typename... Args>
    static auto make_object(U u, Args... args)
    {
        constexpr std::size_t S = sizeof...(Args);
        return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
    }
};

int main()
{
    auto obj = object_maker<int>::make_object(7);
    static_assert(std::is_same_v<decltype(obj), std::unique_ptr<Object<0,int>>>);
}
不幸的是,两者之间没有任何区别

为了解决这个问题,您可以将
make_object
函数包装在模板类中,并使该模板类成为朋友

#include <type_traits>
#include <iostream>
#include <memory>

template<typename U>
struct object_maker;

template<std::size_t S, typename T>
class Object {
private:
    Object(T) {}

    friend struct object_maker<T>;
};


template<typename U>
struct object_maker
{
    template<typename... Args>
    static auto make_object(U u, Args... args)
    {
        constexpr std::size_t S = sizeof...(Args);
        return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
    }
};

int main()
{
    auto obj = object_maker<int>::make_object(7);
    static_assert(std::is_same_v<decltype(obj), std::unique_ptr<Object<0,int>>>);
}
#包括
#包括
#包括
模板
结构对象生成器;
模板
类对象{
私人:
对象(T){}
友元结构对象生成器;
};
模板
结构对象生成器
{
模板
静态自动生成对象(U、Args…Args)
{
constexpr std::size\u t S=sizeof…(Args);
返回std::unique_ptr(新对象(u));
}
};
int main()
{
auto-obj=object\u-maker::make\u-object(7);
静态断言(std::is_same_v);
}

如果你想拥有一个好友模板,你可以像你的例子一样,将该模板的所有安装都设置为好友,也可以将完全专业化设置为好友

#include <type_traits>
#include <iostream>
#include <memory>

template<typename U>
struct object_maker;

template<std::size_t S, typename T>
class Object {
private:
    Object(T) {}

    friend struct object_maker<T>;
};


template<typename U>
struct object_maker
{
    template<typename... Args>
    static auto make_object(U u, Args... args)
    {
        constexpr std::size_t S = sizeof...(Args);
        return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
    }
};

int main()
{
    auto obj = object_maker<int>::make_object(7);
    static_assert(std::is_same_v<decltype(obj), std::unique_ptr<Object<0,int>>>);
}
不幸的是,两者之间没有任何区别

为了解决这个问题,您可以将
make_object
函数包装在模板类中,并使该模板类成为朋友

#include <type_traits>
#include <iostream>
#include <memory>

template<typename U>
struct object_maker;

template<std::size_t S, typename T>
class Object {
private:
    Object(T) {}

    friend struct object_maker<T>;
};


template<typename U>
struct object_maker
{
    template<typename... Args>
    static auto make_object(U u, Args... args)
    {
        constexpr std::size_t S = sizeof...(Args);
        return std::unique_ptr<Object<S, U>>(new Object<S, U>(u));
    }
};

int main()
{
    auto obj = object_maker<int>::make_object(7);
    static_assert(std::is_same_v<decltype(obj), std::unique_ptr<Object<0,int>>>);
}
#包括
#包括
#包括
模板
str