初めて質問させて頂く、やまと言います。
WinXP(SP2)でVC++6.0のMFCアプリケーションを
VC++2005に移行する作業を行っています。
モジュール構成は1つのexeに2つのdllとなっており
この1つのdllのデバッグがうまくいきません。
ネットで調べながら修正していたのですが
壁にぶちあたってしまったのでここで最初からご教示頂ければと思います。
とりあえずソースと最初の実行結果を添付します。
---Core.h---
#ifndef _CORE_H_
#define _CORE_H_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#pragma warning(disable: 4251)
//標準ヘッダファイル
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <comdef.h>
#include <time.h>
//#include <strstrea.h> ←★今回コメントアウト★
#include <strstream> ←★今回追加★
using namespace std; ←★今回追加★
#include <process.h>
#include <new.h>
//Stream が外部公開しているもの
#include Stream.h
#include LogStreamBuffer.h
#endif // _CORE_H_
---Stream.h---
#ifndef _STREAM_H_
#define _STREAM_H_
#ifdef STREAM_EXPORTS
#define STREAM_API __declspec(dllexport)
#else
#define STREAM_API __declspec(dllimport)
#endif
// このクラスは Stream.dll からエクスポートされます
class STREAM_API CStream {
public:
CStream(void);
};
extern STREAM_API int nStream;
STREAM_API int fnStream(void);
////////// 重要 //////////////////////////
//_bstr_tを公開する。
class STREAM_API _bstr_t;
class STREAM_API strstreambuf;
class STREAM_API ostream;
#endif // _STREAM_H_
---LogStreamBuffer.h---
class STREAM_API CLogStreamBuffer : public strstreambuf
{
・・・
}
class STREAM_API CLogStream : public ostream
{
・・・
}
---実行結果---
1>logstreambuffer.h(31) : error C2872: 'strstreambuf' : あいまいなシンボルで
す。
1> 'stream.h(44) の可能性があります : strstreambuf'
1> または 'c:\program files\microsoft visual studio 8
\vc\include\strstream(18) : std::strstreambuf'
1>logstreambuffer.h(31) : error C2504: 'strstreambuf' : 定義されていない基本ク
ラスが宣言されています。
1>logstreambuffer.h(132) : error C2872: 'ostream' : あいまいなシンボルです。
1> 'stream.h(45) の可能性があります : ostream'
1> または 'c:\program files\microsoft visual studio 8\vc\include\iosfwd
(701) : std::ostream'
1>logstreambuffer.h(132) : error C2504: 'ostream' : 定義されていない基本クラス
が宣言されています。
1>logstreambuffer.h(165) : error C2039: 'str' : 'CLogStreamBuffer' のメンバでは
ありません。
1> logstreambuffer.h(30) : 'CLogStreamBuffer' の宣言を確認してください。
1>logstreambuffer.h(223) : error C2039: 'write' : 'CLogStream' のメンバではあり
ません。
1> logstreambuffer.h(131) : 'CLogStream' の宣言を確認してください。
一応、Stream.hの「class STREAM_API strstreambuf;」を
「class STREAM_API std::strstreambuf;」に変更すると
strstreambufに関してエラーは出ないのですが、この修正方法は正しいのでしょうか?
ちなみに、ostreamについて同様な処理をしても別のエラーになります。
それとも、それ以前にCore.hのヘッダファイルの修正方法が間違ってるのでしょうか?
以上、宜しくお願いします。
> 一応、Stream.hの「class STREAM_API strstreambuf;」を
> 「class STREAM_API std::strstreambuf;」に変更すると
> strstreambufに関してエラーは出ないのですが、この修正方法は正しいのでしょうか?
これはstd名前空間に本体があるので正しいと思います。
> ちなみに、ostreamについて同様な処理をしても別のエラーになります。
.hのバージョンで定義されていたostreamは単なるクラスでしたが、
ISO/IEC 14882:2003(VC++2005が準拠している規格)のostreamは
テンプレートの特殊化になっています。具体的には、
template<typename CharT, typename Traits = char_traits<CharT> >
class basic_ostream: ...
といったテンプレートクラスbasic_ostreamがあって、ostreamは、
typedef basic_ostream<char> ostream;
といった定義になっています。そのため、
class std::ostream;
といった宣言をしようとするとエラーになるわけです。
テンプレートやその特殊化のインポート、エクスポートはやったことがなく、
方法が分かりません。申しわけないです。
ヘッダファイル内部に using namespace std; を書かないこと。影響がでかすぎる。
hoge.cpp 中の #include 列の末尾に置くようにするといい鴨しれない。
次に ostream; の先行宣言は class std::ostream; とせずに #include <iosfwd>
回答ありがとうございます。
yoh2さん
>.hのバージョンで定義されていたostreamは単なるクラスでしたが、
>ISO/IEC 14882:2003(VC++2005が準拠している規格)のostreamは
>テンプレートの特殊化になっています。
やはり形式が変わったんですね。
結局、basic_ostreamを使うしかないんですよね?
tetrapodさん
>ヘッダファイル内部に using namespace std; を書かないこと。影響がでかすぎる。
>hoge.cpp 中の #include 列の末尾に置くようにするといい鴨しれない。
>次に ostream; の先行宣言は class std::ostream; とせずに #include <iosfwd>
「using namespace std;」をcppに書くのが安全だと思うのですが
今のところ、どのcppに置いても「'strstreambuf' : あいまいなシンボル」のエラーが
出てしまいます。
あと、「class STREAM_API ostream;」をコメントアウトすると
とりあえず最初のostreamのエラーが出なくなりましたが「#include <iosfwd>」は必要
でしょうか?
それで、テンプレートの特殊化がよくわからない状態で修正を行っています。
LogStreamBuffer.hについては以下の修正でエラーが出なくなりましたが、この修正は正
しいでしょうか?
---LogStreamBuffer.h---
//class STREAM_API CLogStream : public ostream
template <class Elem, class Tr = std::char_traits<Elem> >
class STREAM_API CLogStream : public basic_ostream<Elem, Tr>
{
・・・
};
//
// ログレベルを設定するマニピュレータ
//
// DEBUG
//inline CLogStream&
//LevelDebug(CLogStream& log)
template <class Elem, class Tr>
inline CLogStream<Elem, Tr>&
LevelDebug(CLogStream<Elem, Tr>& log)
{
log.SetLogLevel(LOG_DEBUG);
return log;
}
・・・
//
// 引数のあるマニピュレータのテンプレートクラス
//
//template <class TYPE>
template <class TYPE, class Elem, class Tr>
class OMANIP
{
public:
// コンストラクタ
// OMANIP(void (*f)(CLogStream&, TYPE ), TYPE data)
OMANIP(void (*f)(CLogStream<Elem, Tr>&, TYPE ), TYPE data)
: m_pFunc(f), m_Data(data)
{
}
// マニピュレータのポインター
// void (*m_pFunc)(CLogStream&, TYPE);
void (*m_pFunc)(CLogStream<Elem, Tr>&, TYPE);
// データ
TYPE m_Data;
};
// オペレータ
//template <class TYPE>
//inline CLogStream&
//operator<<(CLogStream& log, const OMANIP<TYPE>& m)
template <class TYPE, class Elem, class Tr>
inline CLogStream<Elem, Tr>&
operator<<(CLogStream<Elem, Tr>& log, const OMANIP<TYPE, Elem, Tr>& m)
{
(*(m.m_pFunc))(log, m.m_Data);
return log;
}
//
// ファイル名を設定するマニピュレータ
//
//inline void
//FileName_(CLogStream& log, const _bstr_t& strFileName)
template <class Elem, class Tr>
inline void
FileName_(CLogStream<Elem, Tr>& log, const _bstr_t& strFileName)
{
log.SetFileName(strFileName);
}
//inline OMANIP<const _bstr_t&>
inline OMANIP<const _bstr_t&, class Elem, class Tr>
FileName(const _bstr_t& strFileName)
{
// return OMANIP<const _bstr_t&>(FileName_, strFileName);
return OMANIP<const _bstr_t&, class Elem, class Tr>(FileName_,
strFileName);
}
結局、以下の箇所でエラーになり、上記と同様な修正を試みているのですが解決に至っ
ていません。。。
---Initialize.h---
#if !defined(AFX_INITIALIZE_H__4CC5C684_BC89_4180_A4FA_EE320A077175__INCLUDED_)
#define AFX_INITIALIZE_H__4CC5C684_BC89_4180_A4FA_EE320A077175__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CInitialize
{
・・・
};
// CLogStreamクラス
STREAM_API extern CLogStream e_Log;←★エラーの箇所★
#endif // !defined
(AFX_INITIALIZE_H__4CC5C684_BC89_4180_A4FA_EE320A077175__INCLUDED_)
1>initialize.h(36) : error C2955: 'CLogStream' : クラス テンプレート を使用する
には テンプレート 引数リストが必要です
1> logstreambuffer.h(133) : 'CLogStream' の宣言を確認してください。
あれからネットを駆使して何とか解決できました!
皆さん、ありがとうございました。
一応うまくいったコードを載せておきます。
---LogStreamBuffer.h---
//class STREAM_API CLogStream : public ostream
template <class Elem, class Tr>
class STREAM_API CLogStream : public std::basic_ostream<Elem, Tr>
{
・・・
};
//
// ログレベルを設定するマニピュレータ
//
// DEBUG
//inline CLogStream&
//LevelDebug(CLogStream& log)
inline CLogStream<char, std::char_traits<char>>&
LevelDebug(CLogStream<char, std::char_traits<char>>& log)
{
log.SetLogLevel(LOG_DEBUG);
return log;
}
・・・
//
// 引数のあるマニピュレータのテンプレートクラス
//
template <class TYPE>
class OMANIP
{
public:
// コンストラクタ
// OMANIP(void (*f)(CLogStream&, TYPE ), TYPE data)
OMANIP(void (*f)(CLogStream<char, std::char_traits<char>>&, TYPE ), TYPE
data)
: m_pFunc(f), m_Data(data)
{
}
// マニピュレータのポインター
// void (*m_pFunc)(CLogStream&, TYPE);
void (*m_pFunc)(CLogStream<char, std::char_traits<char>>&, TYPE);
// データ
TYPE m_Data;
};
// オペレータ
template <class TYPE>
//inline CLogStream&
//operator<<(CLogStream& log, const OMANIP<TYPE>& m)
inline CLogStream<char, std::char_traits<char>>&
operator<<(CLogStream<char, std::char_traits<char>>& log, const OMANIP<TYPE>&
m)
{
(*(m.m_pFunc))(log, m.m_Data);
return log;
}
//
// ファイル名を設定するマニピュレータ
//
inline void
//FileName_(CLogStream& log, const _bstr_t& strFileName)
FileName_(CLogStream<char, std::char_traits<char>>& log, const _bstr_t&
strFileName)
{
log.SetFileName(strFileName);
}
inline OMANIP<const _bstr_t&>
FileName(const _bstr_t& strFileName)
{
return OMANIP<const _bstr_t&>(FileName_, strFileName);
}
---Initialize.h---
#if !defined(AFX_INITIALIZE_H__4CC5C684_BC89_4180_A4FA_EE320A077175__INCLUDED_)
#define AFX_INITIALIZE_H__4CC5C684_BC89_4180_A4FA_EE320A077175__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CInitialize
{
・・・
};
// CLogStreamクラス
//STREAM_API extern CLogStream e_Log;
STREAM_API extern CLogStream<char, std::char_traits<char>> e_Log;
#endif // !defined
(AFX_INITIALIZE_H__4CC5C684_BC89_4180_A4FA_EE320A077175__INCLUDED_)