2013-08-01 65 views
1

我正在试图创建一个日志到std :: cout和一个文件的记录器。这是我的课:无法专用功能模板。超载运算符<<

.h文件中:

class ProblemsManager { 
     (...) 
private: 
     (...) 

    class logger { 
    private: 
     std::ofstream fileStream; 
     static const std::string LOG_PATH; 
    public: 
     logger(); 
     ~logger(); 


    template<class T> 
    friend logger & operator<<(logger &log, const T & bytes) { 
     log.fileStream<<bytes; 
     std::cout<<bytes; 
     return log; 
    } 
    }; 
}; 

.cpp文件

(...) 
const std::string ProblemsManager::logger::LOG_PATH = "F:\\Dropbox\\workspace - Visual Studio\\PEuler\\PEuler\\PEuler.log"; 

ProblemsManager::logger::logger() : fileStream(LOG_PATH,std::ofstream::out) {} 
ProblemsManager::logger::~logger() {} 

然后,如果我尝试做:

ProblemsManager::logger log; 
log<<"test"; 

我得到:

1> f:\ dropbox \ workspace-visual studio \ peuler \ peuler \ problemsmanager.cpp(47):error C3767:'< <':候选函数不可访问 1>可能是朋友函数'F:\保管箱\工作空间 - 视觉工作室\ peuler \ peuler \ problemsmanager.h(37)': '< <'[可经由发现参数依赖查找]

+0

有趣的是,你的模板函数的定义与它们的声明是分开的;我认为这是不可能的,因为每个需要使用模板化定义的文件都无法从声明中生成它们(因为定义本身在完全不同的cpp文件中)。我很惊讶,它甚至编译o.O – Suedocode

+0

'logger'类型是封闭类型'ProblemsManager'的专用类型吗? –

+0

是的,它是私人的。 –

回答

3

您的模板有几个问题,第一个问题是两者仅在参考上有所不同,并且会导致问题。你只需要一个(即读,不写参数):

template<class T> 
    friend logger & operator<<(logger& log, const T & bytes); 
    //          ^^^^^ 

现在第二个问题是,模板应该在某处定义,其中,生成实例化时,编译器可以看到它。这基本上意味着定义必须在标题中,而不是在.cpp文件中。 [*]

除此之外,由于logger类型是私人ProblemsManager,你不能从命名空间级别访问它,所以你必须定义free函数的问题,因为它不能访问嵌套类型。该方案将使得式公开,因此该功能也ProblemsManager的朋友,或者我会建议,只是在类定义里面的模板内联:

class ProblemsManager { 
private: 
    class logger { 
     template<class T> 
     friend logger & operator<<(logger& log, T & bytes) { 
      // implementation goes here 
     } 
    }; 
}; 

[*]这实际上可能是规则的例外,因为作为私人类型,我只能假定在定义ProblemsManager成员的翻译单元中将发生logger和因此operator<<的所有用途。如果是这样的话,你可以忽略这一段。

+0

这似乎解决了这个问题。但现在我得到了1> f:\ dropbox \ workspace - visual studio \ peuler \ peuler \ problemsmanager.cpp(47):error C3767:'<<':候选函数不可访问 1>可能是朋友函数在'f:\ dropbox \ workspace - visual studio \ peuler \ peuler \ problemsmanager.h(37)':'<<'[可以通过依赖于参数的查找] –

+0

我编辑了答案,显示我的代码是在目前 –

+1

@Trollkemada与你最新的代码唯一的问题是'记录器'是私人的。公开它对我来说编译得很好。 – jrok

0

与操作员< <功能不是会员,但朋友,你不能在他们里面使用'this'。您可能想要在那里返回“日志”,并用“日志”适当地限定日志成员。

+0

我已纠正并编辑我的答案。它始终无法编译相同的错误。 –

0

我会给它一个长镜头。

log<<"test"; 

上述呼叫是到操作员呼叫< <功能与记录器&的第一参数和常量字符的第二[5]。

第一次重载可能无法绑定,因为您在引用和传递const对象上重载。第二个失败,因为你正在通过值传递数组,你不能这样做。我只是不确定你的数组为什么不折叠成指针。

你试过在const引用上重载吗?顺便说一句 - 为什么你在价值和参考上超载?

+0

我编辑了我的问题。 (现在我只使用const引用的超载,如你所建议的) –

+0

你仍然有你的记录器私有。我很惊讶编译器在你定义日志变量时不会抱怨它。 – Tomek