インターフェイスのユーザーから実装の詳細を隠し、テンプレート化された関数の広範な使用を避けるために、私は次の概念を考えました。
// data.h
#ifndef DATA_H_
#define DATA_H_
#include <cstddef>
template <size_t N = 0>
class Data
{
public:
const size_t n;
size_t values[N];
Data<N>();
};
#endif // DATA_H_
// data.cpp
#include "data.h"
template <size_t N> Data<N>::Data()
:
n(N),
values()
{
for ( size_t i = 0; i < n; ++i )
{
values[i] = i;
}
}
template class Data<1u>;
template class Data<2u>;
// list.h
#ifndef LIST_H_
#define LIST_H_
#include <cstddef>
#include <memory>
class List
{
private:
std::shared_ptr<void> data;
public:
List(const size_t);
void printData() const;
};
#endif // LIST_H_
// list.cpp
#include "list.h"
#include <iostream>
#include <stdexcept>
#include "data.h"
List::List(const size_t n)
:
data()
{
switch ( n )
{
case 1u:
data = std::static_pointer_cast<void>(std::make_shared<Data<1u>>());
break;
case 2u:
data = std::static_pointer_cast<void>(std::make_shared<Data<2u>>());
break;
default:
throw std::runtime_error("not instantiated..");
}
}
void List::printData() const
{
auto obj = std::static_pointer_cast<Data<>>(data); // my question is about this
std::cout << obj->n << ": ";
for ( size_t i = 0; i < obj->n; ++i )
{
std::cout << obj->values[i] << " ";
}
std::cout << "\n";
}
// main.cpp
#include "list.h"
int main()
{
for ( size_t i = 1; i <= 2; ++i )
{
try
{
List list(i);
list.printData();
}
catch ( ... )
{
return 1;
}
}
}
これを恐ろしいデザインだと考える人もいるかもしれません。素晴らしい代替案がない限り、ここでこれについて議論しないでください。
私の質問はの行についてauto obj = std::static_pointer_cast<Data<>>(data);
ですList::printData()
。ちょっと危険な感じがします。正しいインスタンス化が使用されるという保証はありますか?g++-4.6.3
このコードに対して警告を出さず、期待値を出力します。