如何为可以是字符或字符串的模板类实现方法?

Posted

技术标签:

【中文标题】如何为可以是字符或字符串的模板类实现方法?【英文标题】:how do i implement methods for a template class that can be either char or string? 【发布时间】:2020-02-04 15:53:19 【问题描述】:

我有这门课

template <typename T>
class B
    T x;
public:
    B(char c)
        if(typeid(x)==typeid(char)) x=c;
        else
            string h;
            for(int i=0;i<10;i++) h.push_back(c);
            x=h;
        
    
;

这是一个示例类,如果 x 的类型是 char 我希望 x=c 而如果 x 是字符串我希望 x 是 [c]^10

然后我尝试创建两个对象:

int main()
    B<string> a('f');
    B<char> b('g');     

当 i 对象 b 被实例化时,编译器会在第 10 行产生错误:

[Error] cannot convert 'std::string aka std::basic_string<char>' to 'char' in assignment

我了解错误来自您无法将字符串分配给 char 的事实,但无论如何我都需要完成任务,我该怎么做?

【问题讨论】:

这看起来更像是两个不同的类而不是模板。 如果T 不是char 而不是std::string,会发生什么? @MarekR:模板不必处理所有类型,即使std::uniform_real_distribution也只能处理float/double/long double @Jarod42 我知道模板正在使用鸭子类型。问题的更多细节可以导致更合适的解决方案。 【参考方案1】:

对于 C++17,您可以使用 if constexpr:

template <typename T>
class B

    T x;
public:
    explicit B(char c)
    
        if constexpr (std::is_same_v<T, char>) 
            x = c;
         else 
            // static_assert(std::is_same_v<T, std::string>);
            x = std::string(10, c);
        
    
;

【讨论】:

如果你是 C++17,std::is_same_v&lt;T, char&gt; 也可以使用。【参考方案2】:

在 C++17 之前,这似乎是最简单的可能性:

#include <string>

template<class T>
class B 
    T x;
public:

    B(char c);
;

template<>
B<char>::B(char c) : x(c) 

template<>
B<std::string>::B(char c) : x(std::string(c,10)) 

int main() 
    B<char> a('a');
    B<std::string> b('b');
    //B<int> c('c'); // Linker error

【讨论】:

如果您使用-std=c++17 指定C++17 作为编译器标志,则最高投票也将起作用,假设您的编译器支持C++17。我提出这一点是因为您的陈述暗示 C++17 解决方案不起作用;确实如此。不过,实际指定标准由您自己决定。【参考方案3】:

如果 x 的类型是 char 我想要 x=c 而如果 x 是字符串我想要 x 是 [c]^10

一种方法是创建一个返回正确对象的函数模板。

// Declare the function template.
template <typename T> T make_data(char c);

Define specializations of the function template.
template <> char make_data<char>(char c)

   return c;


template <> make_data<std::string>(char c)

   return std::string(c, 10);

使用它们来实现B

template <typename T>
class B

   T x;
   public:
   B(char c) : x(make_data<T>(c)) 
;

【讨论】:

我无法定义更多的函数、方法或成员 @GuglielmoLaMastra,这是一个相当不寻常的约束。至少要知道,当你在外面的世界时,不太可能施加这样的限制。【参考方案4】:

简单的老式模板专业化:

template <typename T>
class B

    T x;
public:
    explicit B(char c) : x(c)
    
;

template <>
B<std::string>::B(char c) : x(10, c)

https://wandbox.org/permlink/5klGI0poD9mor4WY

【讨论】:

以上是关于如何为可以是字符或字符串的模板类实现方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何为矢量专门化一个类模板?

如何为从C++中的模板继承的类重载赋值运算符

(4.3)数组对象及类数组对象,set的用法,正则表达式的常用方法,蓝桥杯备赛-(生成数组数组去重实现模板字符串的解析新课上线啦)

模板模式讲解二

Spring Boot:如何为删除其余模板编写单元测试用例

c++创建链表为啥要用类模板