Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to allow template function to have friend(-like) access?

How does one modify the following code to allow template function ask_runUI() to use s_EOF without making s_EOF public?

#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";
}
like image 415
CW Holeman II Avatar asked May 28 '09 18:05

CW Holeman II


People also ask

Can template function be a friend?

One-to-one: A template function instantiated with one set of template arguments may be a friend to one template class instantiated with the same set of template arguments. This is also the relationship between a regular non-template class and a regular non-template friend function.

How do I force a template instantiation?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.


2 Answers

If you want a template function to be a friend, you must say so in the class declaration. Change the line that declares the friend function to this:

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

Now, if your class is itself a template, things get a lot more complicated. Template friends are not trivial to do correctly. For that, I'll refer you to what C++ FAQ Lite says on the subject.

like image 99
Michael Kristofik Avatar answered Oct 17 '22 10:10

Michael Kristofik


This worked for me!

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;
}
like image 4
aJ. Avatar answered Oct 17 '22 11:10

aJ.