MAKE VERSION macro? How to do?

Started by
14 comments, last by demonkoryu 16 years, 11 months ago
Quote:Original post by Antheus
Since you mention DWORDS, it's likely you're talking about C++.

*** Source Snippet Removed ***

Nice solution, but...

Quote:
You can also change the types of individual A,B,C,D to be different from 8-bit int, perhaps 16-bit for D, to allow more builds.

And watch it blow up?

Quote:But the best thing is, there is no overhead, there is no storage, and no #defines.

Maybe 4 times as much storage than the macro solution.

Quote:You can optionally make all methods static.

To what effect?

Quote:Excercises left for the reader:
- overload << operator
- overload comparison operators
etc...

Comparison operators. Forgot that you have to define a different type for every version?

For DWORDS, comparison operators are built in.
Advertisement
Quote:Original post by Konfusius
Quote:Original post by Antheus
Since you mention DWORDS, it's likely you're talking about C++.

*** Source Snippet Removed ***

Nice solution, but...

Quote:
You can also change the types of individual A,B,C,D to be different from 8-bit int, perhaps 16-bit for D, to allow more builds.

And watch it blow up?

Why would it blow up?
Quote:
Quote:But the best thing is, there is no overhead, there is no storage, and no #defines.

Maybe 4 times as much storage than the macro solution.

Or maybe no storage. Oh, it's true that the values would appear in the DATA segment, just like with the C preprocessor macro, but there's no need for the additional non-portable DWORD with the template.
Quote:
Quote:You can optionally make all methods static.

To what effect?

So you don't need an instance variable.
Quote:
Quote:Excercises left for the reader:
- overload << operator
- overload comparison operators
etc...

Comparison operators. Forgot that you have to define a different type for every version?

For DWORDS, comparison operators are built in.

So you can compare apple.verision and orange.version and get meaningful results, yes?

Stephen M. Webb
Professional Free Software Developer

Quote:Original post by Bregma
Quote:Original post by Konfusius
Quote:Original post by Antheus
Since you mention DWORDS, it's likely you're talking about C++.

*** Source Snippet Removed ***

Nice solution, but...

Quote:
You can also change the types of individual A,B,C,D to be different from 8-bit int, perhaps 16-bit for D, to allow more builds.

And watch it blow up?

Why would it blow up?


As it stands operator() would fail.

// Fixed operator()// Fixed print using type_traits to avoid the static cast which would // cause errors if sizeof(ver_t) > sizeof(int)typedef unsigned char ver_t;template < ver_t A, ver_t B, ver_t C, ver_t D, typename CompactType = DWORD >struct version{  CompactType operator()() const  {    BOOST_STATIC_ASSERT(4 * sizeof(ver_t) <= sizeof(CompactType));    std::size_t bits = sizeof(ver_t) * CHAR_BITS;    return (A << 3 * bits) | (B << 2 * bits) | (C << bits) | (D);  }  ver_t Version() const { return A; }  ver_t Major() const { return B; }  ver_t Minor() const { return C; }  ver_t Build() const { return D; }private:  template<typename T>  struct print_traits  {     T convert(t)     { return t; }  };  template<>  struct print_traits<char>  {    int convert(char c)    { return static_cast<int>(c); }  };  template<>  struct print_traits<unsigned char>  {    int convert(unsigned char c)    { return static_cast<int>(c); }  };  template<>  struct print_traits<signed char>  {    int convert(signed char c)    { return static_cast<int>(c); }  };   void print() const  {    std::cout << print_traits<ver_t>::convert(A) << '.'               << print_traits<ver_t>::convert(B) << '.'               << print_traits<ver_t>::convert(C) << '.'               << print_traits<ver_t>::convert(D);  }};
Antheus, you should store the "DWORD" value as a value in an enum.

This gives you a compile-time constant if you absolutely need it.
This is all getting a bit too fancy, this is what I have used in the past. The enum is just there is you want to find the patch or major etc.
#ifndef GNL_VERSION_H_#	define GNL_VERSION_H_#	include "GNL_types.h"#	include <string>#	include <sstream>namespace GNL{	///////////////////////////////////////////////////////////////////////////////	///  Build	///  A simple version build number which is sent when connecting to determine	///  if the client is using the correct version of the library	///////////////////////////////////////////////////////////////////////////////	template<GNL::uint8 MAJ,GNL::uint8 MIN,GNL::uint8 PATCH>struct Build{	enum {major = MAJ,minor = MIN,patch = PATCH};	static GNL::uint32 number()	{		static GNL::uint32 version_number = (GNL::uint32)major*1000+minor*100+patch;		return version_number;	}	static std::string str()	{		std::stringstream s;		s <<"OpenGNL-"<<major <<"." <<minor <<"." <<patch; 		return s.str();	}};typedef Build<0,3,1> Version;//this is the build}//GNL#endif//GNL_VERSION_H_
Quote:Original post by Bregma
Why would it blow up?

Because that implementation doesn't work with values greater than 255.

Quote:Or maybe no storage. Oh, it's true that the values would appear in the DATA segment, just like with the C preprocessor macro, but there's no need for the additional non-portable DWORD with the template.

Well, I bet many compilers will store 1 machine word for every version component. And what's that about non-portability? The OP asked for a DWORD (and a macro), nothing more, nothing less.

Quote:
Quote:
Quote:You can optionally make all methods static.

To what effect?

So you don't need an instance variable.

Bad style.

Quote:So you can compare apple.verision and orange.version and get meaningful results, yes?

Yeah, exactly that. if (current_version < needed_version) throw version_error(); or something like that. No need for overengineering.

This topic is closed to new replies.

Advertisement