ページ 11

C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 15:58
by chibago
標題の通りC++(GCC)の可変引数に関してテンプレートが併用できなくて困っております。

コード:

template <typename T>
  void Test<T>::set_data(const int size, ...){
  va_list argptr;
  va_start (argptr, size);

  std::vector<T> result(size, 0.0);
  for (typename std::vector<T>::iterator  itr (result.begin());
                    itr!=result.end(); ++itr){
    *itr= va_arg (argptr, std::vector<T>::value_type);
  }   
  va_end (argptr);
  this->data = result;
}
このように、任意の数の入力を入れた際、この入力をvectorに格納して
メンバ変数に格納しようと考えております。このva_arg関数でテンプレート変数を
使うとコンパイル出来ないようです。(ここだけdoubleと指定すると上手くいきます。)

typedef std::vector<T> vector_T;

等として対応してみましたが上手くいきません。

何か良い方法はございませんでしょうか。

Re: C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 16:11
by beatle
Visual C++ 2010 ほとんど無改造で動きましたよ。

コード:


#include <cstdarg>
#include <vector>
#include <iterator>
#include <iostream>
#include <algorithm>

template <typename T>
class Test
{
public:
	void set_data(const int size, ...);
	void print() const {
		std::copy(data.begin(), data.end(), std::ostream_iterator<T>(std::cout, "\n"));
	}
private:
	std::vector<T> data;
};

template <typename T>
void Test<T>::set_data(const int size, ...){
	va_list argptr;
	va_start (argptr, size);

	std::vector<T> result(size); // ここだけ変更。T型を0.0で初期化しようとしていた。
	for (typename std::vector<T>::iterator itr(result.begin());
		itr!=result.end(); ++itr){
			*itr= va_arg(argptr, std::vector<T>::value_type);
	}
	va_end (argptr);
	this->data = result;
}

int main()
{
	Test<int> t;
	t.set_data(3, 10, 20, 30);
	t.print();
}

Re: C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 16:24
by beatle
Ubuntuのg++でやってみました。確かにコンパイルエラーが出ますね。

コード:

test.cpp: メンバ関数 ‘void Test<T>::set_data(int, ...)’ 内:
test.cpp:27:10: エラー: expected type-specifier
test.cpp:27:10: エラー: ‘)’ が予期されます
test.cpp:27:10: エラー: ‘;’ が予期されます
これは、「std::vector<T>::value_type」が型名かどうか分からないから出ているエラーです。typenameを補って

コード:

            *itr= va_arg(argptr, typename std::vector<T>::value_type);
のようにしましょう。

Re: C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 16:43
by たかぎ
GCCならそんな難しいことをしなくても、次のようにすればよいのでは?
(引数にsizeは不要ですよね?)

コード:

template <typename T>
class Test
{
public:
    void set_data()
    {
    }

    template <class U, class... Params>
    void set_data(U value, Params... params)
    {
        this->data.push_back(value);
        set_data(params...);
    }
private:
    std::vector<T> data;
};
こっちの方がシンプルですし、型安全ですし、TがPOD以外でも使えます。
強い例外安全保障のためにはもう一工夫いりますが、とりあえず上記でも機能は実現できるはずです。
なお、コンパイルするためには、-std=c++0xまたは-std=gnu++0xオプションが必要です。

Re: C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 16:55
by beatle
C++11に走るならGCC 4.4からinitializer_listも使えますね。

コード:

#include <vector>
#include <initializer_list>
#include <iterator>
#include <iostream>
#include <algorithm>

template <typename T>
class Test
{
public:
    void set_data(std::initializer_list<T> init_list)
    {
        data_ = init_list;
    }
    const std::vector<T>& data() const
    {
        return data_;
    }
private:
    std::vector<T> data_;
};

int main()
{
    Test<int> t;
    t.set_data({10, 20, 30});
    std::copy(t.data().begin(), t.data().end(), std::ostream_iterator<int>(std::cout, "\n"));
}

Re: C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 16:59
by chibago
betale様、たかぎ様、
ありがとうございました。

おかげさまで解決いたしました。
(ただcx0は少々抵抗がありますので、標準仕様になってから導入を検討いたしたいと思います。)

Re: C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 17:10
by たかぎ
beatle さんが書きました:C++11に走るならGCC 4.4からinitializer_listも使えますね。
そうですね。シンタックスがかなり変わるので避けていました。

シンタックスが多少変わってもよいなら、C++11でなくても、GCC拡張を使って...

コード:

#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <cstddef>

template <typename T>
class Test
{
public:
    template <std::size_t N>
    void set_data(T const (&data)[N])
    {
        std::vector<T> temp(&data[0], &data[N]);
        this->data.swap(temp);
    }

    void dump()
    {
        std::copy(this->data.begin(), this->data.end(), std::ostream_iterator<T>(std::cout, "\n"));
    }
private:
    std::vector<T> data;
};

int main()
{
    Test<int> t;
    t.set_data((int[]){1, 2, 3});
    t.dump();
}
というのでもよいでしょう。

Re: C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 17:11
by たかぎ
chibago さんが書きました:(ただcx0は少々抵抗がありますので、標準仕様になってから導入を検討いたしたいと思います。)
すでにC++11は国際標準になっています。

Re: C++のva_listとテンプレートの併用

Posted: 2011年11月18日(金) 17:14
by beatle
chibago さんが書きました:(ただcx0は少々抵抗がありますので、標準仕様になってから導入を検討いたしたいと思います。)
ISOはもう通りましたので、既に標準仕様ですけれども。
参考:http://www.open-std.org/jtc1/sc22/wg21/

追記
おうふ。たかぎさんともろかぶり!