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 - Fatal编程技术网

C++ 模板化类专门化,其中模板参数是模板

C++ 模板化类专门化,其中模板参数是模板,c++,templates,C++,Templates,我想知道类似的事情是否可能发生。基本上,我有一个模板类,它偶尔会获取模板类的对象。我想为一个特定的模板化类专门化它(或者只是一个成员函数),但是该类的“泛型”形式 template<typename T, typename S> class SomeRandomClass { //put something here }; template<typename T> class MyTemplateClass { void DoSomething(T &a

我想知道类似的事情是否可能发生。基本上,我有一个模板类,它偶尔会获取模板类的对象。我想为一个特定的模板化类专门化它(或者只是一个成员函数),但是该类的“泛型”形式

template<typename T, typename S>
class SomeRandomClass
{
    //put something here
};

template<typename T>
class MyTemplateClass
{
    void DoSomething(T & t) {
       //...something
    }
};

template<>
void MyTemplateClass< SomeRandomClass<???> >::DoSomething(SomeRandomClass<???> & t)
{
    //something specialized happens here
}
模板
课堂
{
//放点东西在这儿
};
模板
类MyTemplateClass
{
无效剂量测定(T&T){
//……什么
}
};
模板
void MyTemplateClass:DoSomething(SomeRandomClass&t)
{
//这里发生了一些特殊的事情
}

用适当的类型(双精度等)替换问号是可行的,但我希望它保持通用性。我不知道该放什么,因为任何类型都不会被定义。我环顾四周,了解了模板参数,并尝试了各种组合,但都无济于事。谢谢你的帮助

你所需要做的只是在你想保持通用性的基础上建立模板。以您开始的内容为例:

template<typename T, typename S>
void MyTemplateClass< SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S> & t)
{
    //something specialized happens here
}

编辑:这是对不同问题的正确回答

两次使用typename
T
会稍微混淆这个问题,因为它们是单独编译的,并且没有任何连接

您可以重载该方法以获取模板参数:

template <typename T>
class MyTemplateClass
{
    void DoSomething(T& t) { }

    template <typename U,typename V>
    void DoSomething(SomeRandomClass<<U,V>& r) { }
};
模板化调用将被选择为匹配重载,而无需显式重新指定类型

编辑:

使用模板专门化对
DoSomething
的过载没有影响。如果你把这个类专门化如下

template <>
class SomeRandomClass <int,double>
{
    // something here...
};
模板
课堂
{
//这里有些东西。。。
};
然后,上面的重载将很高兴地耗尽这个专门的实现。只需确保专用模板和默认模板的接口匹配即可


如果您想要专门化
DoSomething
以获取
SomeRandomClass
的特定类型对,那么您已经失去了通用性…这就是专门化的含义。

可以像这样专门化类

template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
    void DoSomething(SomeRandomClass<T,S>& t) { /* something */ }
};
模板
模板
类MyTemplateClass
{
void DoSomething(SomeRandomClass&t){/*someone*/}
};
不可能只对成员方法进行专门化,因为专门化是作为一个整体对类进行的,您必须定义一个新类。但是,你可以这样做

template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
    void DoSomething(SomeRandomClass<T,S>& t);
};

template <>
template <typename T,typename S>
void MyTemplateClass<SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S>& t)
{
    // something
}
模板
模板
类MyTemplateClass
{
无效剂量测定(等级&t);
};
模板
模板
void MyTemplateClass::DoSomething(SomeRandomClass&t)
{
//某物
}

将声明和定义分开。

我不完全确定为什么@Ryan Calhoun,但这里有一个更简洁的例子:

// class we want to specialize with later on
template<typename T, typename S>
struct SomeRandomClass
{
    int myInt = 0;
};

// non-specialized class
template<typename T>
struct MyTemplateClass
{
    void DoSomething(T & t) 
    {
       std::cout << "Not specialized" << std::endl;
    }
};

// specialized class
template<typename T, typename S>
struct MyTemplateClass< SomeRandomClass<T, S> >
{
    void DoSomething(SomeRandomClass<T,S> & t) 
    {
       std::cout << "Specialized" << std::endl;
    }
};
然后让我们再次声明我们的
MyTemplateClass
,但是这次没有模板化(因为我们没有专门化),所以我们将其称为
MyNonTemplatedClass

// concept to test for whether some type is SomeRandomClass<T,S>
template<typename T>
struct is_random_class : std::false_type{};

template<typename T, typename S>
struct is_random_class<SomeRandomClass<T,S>> : std::true_type{};
class MyNonTemplatedClass
{
    
    public:
    template<typename T>
    void DoSomething(T & t) 
    {
       DoSomethingHelper(t, typename is_random_class<T>::type());
    }
    // ...
    private:
    //use tag dispatch. If the compiler is smart it won't actually try to instantiate the second param
    template<typename T>
    void DoSomethingHelper(T&t, std::true_type)
    {
        std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
    }
    
    template<typename T>
    void DoSomethingHelper(T&t, std::false_type)
    {
        std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
    }
};
  • t
    与以前一样;我们正在传递类型为
    T&
  • typename是\u random\u class::type()
    • is_random_class
      是我们的概念,因为它源于
      std::true_type
      std::false_type
      ,它将在类中定义一个
      ::type
      (谷歌的“类型特征”)
    • ::type()
      “实例化”由
      指定的类型是\u random\u class::type
      。我用引号把它说出来,因为我们真的要把它扔掉,就像我们后面看到的那样
    • typename
      是必需的,因为编译器不知道
      是\u random\u clas::type
      实际命名类型
现在我们准备看一下MyNonTemplatedClass的其余部分:

// concept to test for whether some type is SomeRandomClass<T,S>
template<typename T>
struct is_random_class : std::false_type{};

template<typename T, typename S>
struct is_random_class<SomeRandomClass<T,S>> : std::true_type{};
class MyNonTemplatedClass
{
    
    public:
    template<typename T>
    void DoSomething(T & t) 
    {
       DoSomethingHelper(t, typename is_random_class<T>::type());
    }
    // ...
    private:
    //use tag dispatch. If the compiler is smart it won't actually try to instantiate the second param
    template<typename T>
    void DoSomethingHelper(T&t, std::true_type)
    {
        std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
    }
    
    template<typename T>
    void DoSomethingHelper(T&t, std::false_type)
    {
        std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
    }
};
然后,我们在只编译适当分支的
if constexpr
表达式中使用它(并在编译时丢弃另一个分支,因此检查在编译时进行,而不是在运行时进行):


如果要使用提供模板结构作为模板参数(打算在内部使用),而不需要对其进行专门化,请执行以下操作:

下面是一个示例,它将类型作为模板参数附加到给定模板sfinae结构的元组中:

template<typename Tuple, typename T, template<typename> class /*SFINAEPredicate*/>
        struct append_if;

        template<typename T, template<typename> class SFINAEPredicate, typename ... Types>
        struct append_if<std::tuple<Types...>, T, SFINAEPredicate>
        {
            using type = typename std::conditional<SFINAEPredicate<T>::value,
                    std::tuple<Types..., T>, std::tuple<Types...>>::type;
        };


    // usage
    using tuple_with_int = append_if<std::tuple<>, int, std::is_fundamental>;
模板
结构append_if;
模板
结构附加\u如果
{
使用type=typename std::conditional::type;
};
//用法
使用tuple_和_int=append_if;

这可以从C++11开始使用。

不完全是这样。这看起来只是DoSomething成员的重载,而不是类本身的专门化。你是对的,但不管你是传递专门化类还是常规模板,方法重载都没有区别。我终于明白你的要求了。这个答案完全是反向的。我想差不多就是这样,但是我无法编译(使用g++或intel)。我认为,将模板放在那里会使编译器混淆,不认识到这是一种专门化(即需要有一个模板,对吗?),如果在2010年您希望您的代码在rhel4和rhel5上使用gcc进行编译,并在windows xp上使用visual studio 2008进行编译,这也是你编写它的方式。你能用同样的方式专门化模板函数吗?@Mirco只是一个裸函数,不是类的一部分?对于这种情况,您实际上不需要初始的空模板,因为您没有要专门化的包含模板类模板std::list fun(void){/*return sth*/}?仅专门针对退货类型?我不确定这样的部分专业化是否被允许。但这将是一个很好的问题,张贴和得到答案。
template<class T>
constexpr bool is_random_class_v = is_random_class<T>::value;
struct MyNonTemplatedClass
{
    template<class T>
    void DoSomething(T& t) 
    {
        if constexpr(is_random_class_v<T>)
            std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
        else
            std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
    }
};
struct MyNonTemplatedClass
{
    template<class T>  requires is_random_class_v<T>
    void DoSomething(T& t)
    {
        std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
    }
    
    template<class T> requires !is_random_class_v<T>
    void DoSomething(T&) 
    {
        std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
    }
};
template<typename Tuple, typename T, template<typename> class /*SFINAEPredicate*/>
        struct append_if;

        template<typename T, template<typename> class SFINAEPredicate, typename ... Types>
        struct append_if<std::tuple<Types...>, T, SFINAEPredicate>
        {
            using type = typename std::conditional<SFINAEPredicate<T>::value,
                    std::tuple<Types..., T>, std::tuple<Types...>>::type;
        };


    // usage
    using tuple_with_int = append_if<std::tuple<>, int, std::is_fundamental>;