Jump to content

  • Log In with Google      Sign In   
  • Create Account


#Actualkloffy

Posted 14 March 2013 - 03:07 PM

Ok, so here is an alternative. The static member function check is still pretty ugly (a lot of code duplication). Luckily, the "client" never has to look at it.

template<typename Target, typename Source>
struct is_convertible_to
{
private:
	template<class U, class Enable = typename std::enable_if<!std::is_member_pointer<decltype(&U::to)>::value>::type>
	static std::true_type check(int);
	template<class U>
	static std::false_type check(...);

public:
	typedef decltype(check<conversion<Target, Source>>(0)) type;
	static const bool value = type::value;
};

template<typename Target, typename Source>
struct is_convertible_from
{
private:
	template<class U, class Enable = typename std::enable_if<!std::is_member_pointer<decltype(&U::from)>::value>::type>
	static std::true_type check(int);
	template<class U>
	static std::false_type check(...);

public:
	typedef decltype(check<conversion<Target, Source>>(0)) type;
	static const bool value = type::value;
};

 

Now, one can write the following functions:

template<typename Target, typename Source, typename Enable = void>
struct conversion
{
	//static Target to(Source const& value);
	//static Source from(Target const& value);
};

template<typename Target, typename Source>
typename std::enable_if<is_convertible_to<Target, Source>::value, Target>::type
conversion_cast(Source const& value)
{
	return conversion<Target, Source>::to(value);
}

template<typename Target, typename Source>
typename std::enable_if<!is_convertible_to<Target, Source>::value && is_convertible_from<Source, Target>::value, Target>::type
conversion_cast(Source const& value)
{
	return conversion<Source, Target>::from(value);
}

 

Finally, all this work is to allow the user to write conversions as specializations of the conversion template. Here is a trivial example:

template<>
struct conversion<int, float>
{
	static int to(float const& value)
	{
		return static_cast<int>(value);
	}

	static float from(int const& value)
	{
		return static_cast<float>(value);
	}
};

 

Which would be used as follows:

conversion_cast<int>(1.0f);
conversion_cast<float>(1);

 

So, the point of conversion_cast is to be extensible to arbitrary user defined types. The motivation was that I was integrating different libraries, which required conversions back and forth between types within those libraries. This seems like pretty basic stuff. Am I reinventing the wheel?


#2kloffy

Posted 14 March 2013 - 02:59 PM

Ok, so here is an alternative. The static member function check is still pretty ugly (a lot of code duplication). Luckily, the "client" never has to look at it.

template<typename Target, typename Source>
struct is_convertible_to
{
private:
	template<class U, class Enable = typename std::enable_if<!std::is_member_pointer<decltype(&U::to)>::value>::type>
	static std::true_type check(int);
	template<class U>
	static std::false_type check(...);

public:
	typedef decltype(check<conversion<Target, Source>>(0)) type;
	static const bool value = type::value;
};

template<typename Target, typename Source>
struct is_convertible_from
{
private:
	template<class U, class Enable = typename std::enable_if<!std::is_member_pointer<decltype(&U::from)>::value>::type>
	static std::true_type check(int);
	template<class U>
	static std::false_type check(...);

public:
	typedef decltype(check<conversion<Target, Source>>(0)) type;
	static const bool value = type::value;
};

 

Now, one can write the following functions:

template<typename Target, typename Source, typename Enable = void>
struct conversion
{
	//static Target to(Source const& value);
	//static Source from(Target const& value);
};

template<typename Target, typename Source>
typename std::enable_if<is_convertible_to<Target, Source>::value, Target>::type
conversion_cast(Source const& value)
{
	return conversion<Target, Source>::to(value);
}

template<typename Target, typename Source>
typename std::enable_if<!is_convertible_to<Target, Source>::value && is_convertible_from<Source, Target>::value, Target>::type
conversion_cast(Source const& value)
{
	return conversion<Source, Target>::from(value);
}

 

Finally, all this work is to allow the user to write conversions as specializations of the conversion template. Here is a trivial example:

template<>
struct conversion<int, float>
{
	static int to(float const& value)
	{
		return static_cast<int>(value);
	}

	static float from(int const& value)
	{
		return static_cast<float>(value);
	}
};

 

Which would be used as follows:

conversion_cast<int>(1.0f);
conversion_cast<float>(1);

 

So, the point of conversion_cast is to be extensible to arbitrary user defined types. The motivation was that I was integrating different libraries, which required conversions back and forth between types in those libraries. This seems like pretty basic stuff. Am I reinventing the wheel?


#1kloffy

Posted 14 March 2013 - 02:58 PM

Ok, so here is an alternative. The static member function check is still pretty ugly (a lot of code duplication). Luckily, the "client" never has to look at it.
template<typename Target, typename Source>
struct is_convertible_to
{
private:
	template<class U, class Enable = typename std::enable_if<!std::is_member_pointer<decltype(&U::to)>::value>::type>
	static std::true_type check(int);
	template<class U>
	static std::false_type check(...);

public:
	typedef decltype(check<conversion<Target, Source>>(0)) type;
	static const bool value = type::value;
};

template<typename Target, typename Source>
struct is_convertible_from
{
private:
	template<class U, class Enable = typename std::enable_if<!std::is_member_pointer<decltype(&U::from)>::value>::type>
	static std::true_type check(int);
	template<class U>
	static std::false_type check(...);

public:
	typedef decltype(check<conversion<Target, Source>>(0)) type;
	static const bool value = type::value;
};
Now, one can write the following functions:
template<typename Target, typename Source, typename Enable = void>
struct conversion
{
	//static Target to(Source const& value);
	//static Source from(Target const& value);
};

template<typename Target, typename Source>
typename std::enable_if<is_convertible_to<Target, Source>::value, Target>::type
conversion_cast(Source const& value)
{
	return conversion<Target, Source>::to(value);
}

template<typename Target, typename Source>
typename std::enable_if<!is_convertible_to<Target, Source>::value && is_convertible_from<Source, Target>::value, Target>::type
conversion_cast(Source const& value)
{
	return conversion<Source, Target>::from(value);
}
Finally, all this work is to allow the user to write conversions as specializations of the conversion template. Here is a trivial example:
template<>
struct conversion<int, float>
{
	static int to(float const& value)
	{
		return static_cast<int>(value);
	}

	static float from(int const& value)
	{
		return static_cast<float>(value);
	}
};
Which would be used as follows:
conversion_cast<int>(1.0f);
conversion_cast<float>(1);
So, the conversion_cast is extensible to arbitrary types. The motivation was that I was integrating different libraries, which required conversions back and forth between types in those libraries. This seems like pretty basic stuff. Am I reinventing the wheel?

PARTNERS