Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

c++ - enable_if in template Parameters Creates Template Redefinition Error

In this answer what I really wanted to do is define a typename in my template parameters which could be used in the cast and return.

So this:

template <typename T>
typename std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type caster(T value){ return reinterpret_cast<unsigned char&>(value); }

Would become this:

template <typename T, typename R = std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type >
R caster(T value){ return reinterpret_cast<R&>(value); }

This works and behaves as desired for a single template specialization, but say that I add another specialization:

template <typename T, typename R = std::enable_if<sizeof(short) == sizeof(T), short>::type>
R caster(T value){ return reinterpret_cast<R&>(value); }

Now I get an error:

error C2995: 'R caster(T)' : function template has already been defined

Is there a way to convince the compiler that only one of these specializations will actually build for any given call?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

No, there isn't. Template default arguments are just that, defaults. Any user could call caster<short, short>, which would match both overloads.

However, it would be possible to add more dummy arguments.

template <typename T,
          typename R = typename std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type >
R caster(T value) { return reinterpret_cast<R&>(value); }

template <typename T,
          typename R = typename std::enable_if<sizeof(short) == sizeof(T), short>::type,
          typename = void>
R caster(T value) { return reinterpret_cast<R&>(value); }

(Also note the added typename.)


However, since all bodies are identical, I probably wouldn't go with overloads.

template <std::size_t N>
struct cast_result;

template <>
struct cast_result<sizeof(std::uint8_t)> {
  typedef std::uint8_t type;
};

template <>
struct cast_result<sizeof(std::uint16_t)> {
  typedef std::uint16_t type;
};

...

template <typename T, typename R = typename cast_result<sizeof(T)>::type>
R caster(T value) {
  return reinterpret_cast<R&>(value);
}

A final note: this use of reinterpret_cast is a violation of the aliasing rules. However, that's easily fixed:

template <typename T, typename R = typename cast_result<sizeof(T)>::type>
R caster(T value) {
  R result;
  std::memcpy(&result, &value, sizeof result);
  return result;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...