ページ 1 / 1
テンプレートを用いた関数のオーバーロードについて
Posted: 2012年1月04日(水) 19:05
by MoNoQLoREATOR
突然ですが、下記のソースコードをコンパイルすると「4 オーバーロードのどれも、すべての引数の型を変換できませんでした」というエラーが出ます(160行目)。
► スポイラーを表示
※ちなみに、内容はバイナリファイルを扱うクラスの定義です。
コード:
#include <stdio.h>
#include <bitset>
#include <fstream>
#include <string>
#include <vector>
#include <windows.h>
using namespace std;
struct addsize{
void * myadd;
long mysize;
string * stradd;
bool addmode;
void strinit(string & input, long size){
stradd = &input;
addmode = true;
mysize = size;
}
addsize(string &input, long & size){ strinit(input, size); }
addsize(string &input){ strinit(input, -1); }
template <typename X>
void init(X & address, long size){
addmode = false;
myadd = address;
mysize = size;
}
template <typename X>
addsize(X & address, long & size){ init(address, size); }
template <typename X>
addsize(X & address){ init(address, -1); }
};
class bfilew{
string fName;
bool crePerm;
ofstream ofs;
public:
bool state;
bfilew(){}
bool init(const string &fileName, bool createPermission = true){
state = true;
if(!createPermission && GetFileAttributes(fileName.c_str() )!=-1) state = false;
if(!state) return false;
fName = fileName;
crePerm = createPermission;
ofs.open(fileName.c_str(), ios::binary|ios::app);
if(!ofs){ state=false; return false; }
return true;
}
bfilew(const string &fileName, bool createPermission = true){ init(fileName, createPermission); }
bfilew & clear(){
if(!state) return *this;
ofs.close();
ofs.open(fName.c_str(), ios::binary);
return *this;
}
bfilew & operator! (){
clear();
return *this;
}
bfilew & operator<< (const char * output){
if(!state) return *this;
ofs.write(output, strlen(output)*sizeof(char) );
return *this;
}
bfilew & operator<< (const string & output){
*this << output.c_str();
return *this;
}
bfilew & operator<< (const addsize & output){
if(!state) return *this;
if(output.addmode) *this << output.stradd->substr(0, output.mysize).c_str();
else ofs.write( (const char *)output.myadd, output.mysize);
return *this;
}
template <typename X>
bfilew & operator<< (const X &output){
if(!state) return *this;
ofs.write( (const char *)&output, sizeof(output) );
return *this;
}
bfilew & close(){ ofs.close(); }
};
class bfile : public bfilew{
vector<char> content;
int contPoint;
size_t unsint;
public:
bfile(){}
bool init2(const string &fileName, bool createPermission = true){
state = true;
if(!createPermission && GetFileAttributes(fileName.c_str() )!=-1) return state = false;
contPoint = 0;
unsint = 0;
ifstream ifs(fileName.c_str(), ios::binary);
int contNum = 0;
while(!ifs.eof() ){
content.resize(contNum+1);
ifs.read( (char*)&(content[contNum]), sizeof(char) );
contNum++;
}
state = init(fileName, createPermission);
return state;
}
bfile(const string &fileName, bool createPermission = true){ init2(fileName, createPermission); }
template <typename X>
bfile & read (X &input){
if(!state) return *this;
memcpy(&input, &content[0]+contPoint, sizeof(input) );
contPoint += sizeof(input);
return *this;
}
bfile & operator>> (addsize &input){
if(!state) return *this;
if(input.addmode){
char c;
size_t num = input.mysize;
if(input.mysize==-1) num = unsint;
for(size_t i=0;i<num;i++){
read(c);
*(input.stradd) += c;
}
}
else{
size_t size = input.mysize;
if(input.mysize==-1) size = unsint;
memcpy(input.myadd, &content[0]+contPoint, size);
contPoint += size;
}
return *this;
}
bfile & operator>> (string & input){
*this >> addsize( (string &)input, (long)unsint);
return *this;
}
template <typename X>
bfile & operator>> (X &input){
read(input);
if(sizeof(unsint) >= sizeof(input) ){
unsint = 0;
memcpy(&unsint, &input, sizeof(input) );
}
return *this;
}
};
これは、
コード:
addsize(string &input, long & size){ strinit(input, size); }
addsize(string &input){ strinit(input, -1); }
template <typename X>
addsize(X & address, long & size){ init(address, size); }
template <typename X>
addsize(X & address){ init(address, -1); }
この4つの内のどのコンストラクタを呼び出せば良いのか判断がつかないためにエラーになっているはずなのですが、どのように対処すれば良いのでしょうか?
bfileやbfilewクラスのメンバ関数では、テンプレートを使用しているものよりも型が明示されているものの方が優先的に呼び出され、エラーも出ないのですが、もしかしてコンストラクタの場合は駄目なのですか?
ご教授よろしくお願いいたします。
Re: テンプレートを用いた関数のオーバーロードについて
Posted: 2012年1月04日(水) 19:41
by beatle
MoNoQLoREATOR さんが書きました:bfileやbfilewクラスのメンバ関数では、テンプレートを使用しているものよりも型が明示されているものの方が優先的に呼び出され、エラーも出ないのですが、もしかしてコンストラクタの場合は駄目なのですか?
そんなことはないと思いますけど.
問題なのは,(int)にキャストしているのにint &型の引数に渡そうとしていることです.
int型のリテラルはint &型には渡せません.const int &型になら渡せます.
コード:
void f(int& i) {}
int main()
{
int a;
f(a); // OK
f((int)a); // ERROR
}
ということですね.
Re: テンプレートを用いた関数のオーバーロードについて
Posted: 2012年1月04日(水) 19:41
by beatle
それから,これは興味本位なのですが,どうして内容を変更しないのにlong &で受け取ろうとしているのでしょうか?
Re: テンプレートを用いた関数のオーバーロードについて
Posted: 2012年1月04日(水) 20:17
by MoNoQLoREATOR
そこでしたか。ずっとテンプレートが原因だと思い込んで気づきませんでした。ありがとうございます。
"long"型に明示的にキャストすると自動的には"long &"型に変換してくれないのですね。
そして"unsigned long"型を"long"型には自動変換してくれるけど"long &"型には自動変換してくれない・・・と。
beatle さんが書きました:それから,これは興味本位なのですが,どうして内容を変更しないのにlong &で受け取ろうとしているのでしょうか?
addsizeは書き込み先のアドレスと書き込みサイズの情報を渡したい場合に<<演算子の右辺に渡します。さて、例えばバイナリデータを記録するとき、
「あるデータのデータサイズ」「あるデータ」
というように、読み込むべきデータのサイズをそのデータの前に置いておくことが多いのではないかと思います。
ということは先ほど読み込んだサイズをaddsizeの第2引数に指定したいという場面が多々生じるはずです。
しかしこのとき、某引数を単なる"long"型にしてしまうと、
コード:
size_t num=0;
int a[10];
bfile f("text.txt");
f >> num >> addsize(a, num);
などとした場合に、addsize(&c, num)の部分が先に翻訳されてしまい、読み込むべきデータサイズが初期値のまま(この場合0)になってしまいます。
そういった理由から、"long &"型となっています。
Re: テンプレートを用いた関数のオーバーロードについて
Posted: 2012年1月04日(水) 20:44
by beatle
キャストした時点で右辺値になりますから,左辺値を必要とするX &型の引数としては渡せません.
コード:
int i;
(int)i = 0; // ERROR
ということです.
Re: テンプレートを用いた関数のオーバーロードについて
Posted: 2012年1月04日(水) 22:03
by MoNoQLoREATOR
・・・はて?
どこの箇所でそれが発生しますか?
ちなみに
(int)(i=0);
とすれば解決できると思うのですが、どうなのでしょう。
Re: テンプレートを用いた関数のオーバーロードについて
Posted: 2012年1月05日(木) 00:57
by tk-xleader
>・・・はて?
>どこの箇所でそれが発生しますか?
型変換をするとその式は代入可能な左辺値ではなくて右辺値になります。ですから、
コード:
addsize( (string &)input, (long)unsint); //第二引数において、long&にlongの右辺値を渡そうとしている。
がエラーになるわけですが、これはすなわち
コード:
(int)i = 0; //(int)i は右辺値であるから、代入不可能
と本質的に同じエラーということです。
要は、constなしの参照は、代入可能な左辺値オブジェクトしか受け付けないのです。
Re: テンプレートを用いた関数のオーバーロードについて
Posted: 2012年1月05日(木) 17:30
by MoNoQLoREATOR
なるほどそういうことでしたか。
大変お世話になりました。ありがとうございました。