次のコードを書きました。
g++ -x c++ - -std=gnu++11 -Wall -Wextra -Werror -Wconversion <<__EOF && ./a && echo -e "\e[1;31mOK\e[0m" || echo -e "\e[1;31mfailed!\e[0m"
#include <functional>
#include <vector>
#include <cstdint>
template< typename T >
struct traits_type
{
typedef std::uint8_t op_type;
// ... typedefs
};
template< typename T, typename traits = traits_type< T > >
struct generator
{
typedef typename traits::op_type op_type;
// typedefs...
void operator () () const { return; }
template< typename ...OPS >
void operator () (op_type const op, OPS && ...ops)
{
sequence.push_back(op);
return operator () (std::forward< OPS >(ops)...);
}
// member functions etc...
std::vector< op_type > sequence;
};
int main()
{
struct T { }; // Some type, which does not concern us in this context.
generator< T > g;
g(0b00000000, 0b10101010);
g(0b01010101);
// ... using of g.sequence, say, in state machine
return 0;
}
__EOF
意図したとおり、このコードを使用すると、いくつかの (いわゆる) 「オペコード」のシーケンスを作成できます。ただし、数値リテラル0b00000000
は int として扱われます。これは、最終的に、より大きな符号付き整数型からより小さな符号なし整数型への変換があるという事実につながります。望ましくない副作用が生じる可能性があります。C++ では、サイズが 1 バイトの符号なし整数型を示すサフィックスはありません。純粋なC++11を使用してこれを回避するにはどうすればよいですか? これはコードの肥大化 (複数の括弧と-wrapper 関数static_cast
に名前を付けるための少なくとも 1 つの記号) につながるため、 および他のものは使用したくありません。static_cast
解決策は、ユーザー定義のリテラル、たとえば0b00000000_op
、より見栄えの良いを使用することですo(0b00000000)
。ただし、演算子は次のような関数テンプレートである必要があります。
template< template T, typename traits = type_traits< T > >
constexpr
typename traits::op_type
operator "" _op (typename traits::op_type && op)
{
return std::move(op);
}
しかし、C++11にはそのような構文はありません...そしてT
もしあればテンプレートパラメータをどうするのですか?