【问题标题】:How to allow template function to have friend(-like) access?如何允许模板功能有朋友(-like)访问?
【发布时间】:2010-10-29 16:23:07
【问题描述】:

如何修改以下代码以允许模板函数ask_runUI() 使用s_EOF 而无需公开s_EOF

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
class AskBase {
protected:
    std::string m_prompt;
    std::string m_answer; 
    virtual bool validate(std::string a_response) = 0;
public:
    AskBase(std::string a_prompt):m_prompt(a_prompt){}
    std::string prompt(){return m_prompt;}
    std::string answer(){return m_answer;}
    static int const s_EOF = -99;
    static int const s_BACKUP = -1;
    static int const s_OK = 1;
    int ask_user();
};
template<typename T> class Ask : public AskBase{
public:
    Ask(std::string a_prompt):AskBase(a_prompt){}
    bool validate(std::string a_response);
};
template<> bool Ask<std::string>::validate(std::string a_response){return true;}
template<> bool Ask<int>::validate(std::string a_response){int intAnswer;
    return (std::stringstream(a_response) >> intAnswer);}
int AskBase::ask_user(){
    for(;;){
        std::cout << "Enter " << m_prompt;
        std::string response;
        getline(std::cin, response);
        if (std::cin.eof())
            return s_EOF;
        else if (response == "^")
            return s_BACKUP;
        else if (validate(response)){
            m_answer = response;
            return s_OK;
        }
    }
    return s_EOF;
}
template<typename T> int ask_runUI(T& a_ui){
    int status = AskBase::s_OK;
    for (typename T::iterator ii=a_ui.begin();
            status!=AskBase::s_EOF && ii!=a_ui.end();
            ii+=((status==AskBase::s_BACKUP)?((ii==a_ui.begin())?0:-1):1)
        status = (*ii)->ask_user();
    return (status == AskBase::s_OK);
}
int main(){
    std::vector<AskBase*> ui;
    ui.push_back(new Ask<std::string>("your name: "));
    ui.push_back(new Ask<int>("your age: "));
    if (ask_runUI(ui))
        for (std::vector<AskBase*>::iterator ii=ui.begin(); ii!=ui.end(); ++ii)
            std::cout << (*ii)->prompt() << (*ii)->answer() << std::endl;
    else
        std::cout << "\nEOF\n";
}

【问题讨论】:

  • 下次请使用int ask_runUI()(将``标记为代码)。
  • 如果您要返回号码,为什么要保密?
  • 我扩展了示例以显示只有 AskBase::ask_user() 返回 s_EOF,它仅由 ask_runUI() 使用。

标签: c++ function templates friend


【解决方案1】:

如果你想让模板函数成为朋友,你必须在类声明中这样说。将声明友元函数的行更改为:

template <typename T> 
friend int ask_runUI(T& a_ui);

现在,如果您的类本身就是一个模板,那么事情就会变得复杂得多。模板朋友要正确地做并非易事。为此,我将向您推荐 C++ FAQ Lite 关于该主题的内容。

【讨论】:

    【解决方案2】:

    这对我有用!

    class AskBase {
    public:
        AskBase(){}
        template<typename T> 
        friend int ask_runUI(T& a_ui);
    private:
        static int const    s_EOF = -99;
        static int const    s_BACKUP = -1;
        static int const    s_NULL = 0;
        static int const    s_OK = 1;
    };
    //int ask_runUI()
    template<typename T> 
    int ask_runUI(T& a_ui)
    {
        return AskBase::s_NULL;
    }
    

    【讨论】:

    • 这是经典的模板方法交友反模式。这与公开所有成员基本相同,因为现在任何人都可以编写自己的 ask_runUI() 版本
    • 他们可以,但他们是否会意外地这样做,却没有意识到他们正在做的事情?特别是如果 ask_UI 与类在同一个命名空间中,如果他们在类的接口内四处寻找,那么他们肯定知道他们正在破坏封装吗?
    【解决方案3】:

    最简单的大概是用枚举替换static int const成员,不要乱用friends:

    
    class AskBase {
    public:
        enum { Eof = -99, Null = 0, Ok = 1, Backup = -1 };
        ...
    };
    

    【讨论】:

    • -1。我看不出这会如何改变任何事情——您已宣布为公共的枚举在所有物质方面都等同于仅将静态 const int 成员公开。如果我遗漏了一些区别,请说出来,我会重新考虑。
    • 区别在于编译器不必为静态成员变量分配空间。优点是简单。
    • 嗯,我做了一些研究,结果比我想象的要奇怪。一方面,如果您只是在类定义中声明和初始化静态 const int 成员而不在命名空间级别定义它们(即没有在命名空间级别编写“statict const int AskBase::s_Eof;”等) 则永远不会分配空间。但是,编译器只允许您将 s_Eof 作为右值引用(例如,绑定到非常量引用将在链接时失败!!)请参见此处:stackoverflow.com/questions/272900/…,尤其是 Richard Corden 的回答。
    猜你喜欢
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    相关资源
    最近更新 更多