   [c++] checking at compile time whether a template instantiation is possible
  I am trying to write a conversion function in C++ that takes two arbitrary types, and tries it's best at doing a conversion. (The context for this is a scripting framework for an existing application.).If possible, it should do a boost::numeric_cast. The second choice is an attempt at a boost::lexical_cast. All other cases will result in a failed conversion. My current (broken) attempt looks like this:template<typename TDestination, typename TSource>bool Convert(TDestination& destination, TSource source)  {  return Convertor< TDestination, TSource,CanDoNumericCast<TSource, TDestination>::value,CanDoLexicalCast<TSource, TDestination>::value> ::Convert(destination, source);  }The Convertor class is a template class with specializations like this://general casetemplate<typename TDestination,    typename TSource,    bool TCanUseNumericCast,    bool TCanUseLexicalCast>struct Convertor  {  static bool Convert(TDestination& o_destination, TSource i_source)    {    return false;    }  };//specialization for numerical casttemplate<typename TDestination,    typename TSource,    bool TCanUseLexicalCast>struct Convertor<TDestination, TSource, true, TCanUseLexicalCast>  {  static bool Convert(TDestination& destination, TSource source)    {    try { destination = boost::numeric_cast<TDestination>(source); return true; }    catch (boost::numeric::positive_overflow&) { //do stuff }    catch (boost::numeric::negative_overflow&) { //do stuff }    catch (boost::numeric::bad_numeric_cast&) { //do stuff }    return false;    }  };//specialization for lexical casttemplate<typename TDestination,    typename TSource>struct Convertor<TDestination, TSource, false, true>  {  static bool Convert(TDestination& destination, TSource source)    {    try { destination = boost::lexical_cast<TDestination>(source); return true; }    catch (boost::bad_lexical_cast&) { //do stuff }    return false;    }  };The only thing needed at this point is the CanDoNumericCast and CanDoLexicalCast classes. I triedtemplate<typename TDestination, typename TSource>class CanDoLexicalCast  {  private:    typedef char Small;    class Big {char dummy[2];};    static Small Test(TSource source) { TDestination dest = boost::lexical_cast<TDestination>(source); return Small(); }    static Big Test(...);    static TSource MakeTSource();  public:    enum { value = sizeof(Test(MakeTSource())) == sizeof(Small) };  };This doesn't work. I based this on the "Substitution Failure Is Not An Error" principle, hoping there would also be a rule "Compilation Failure Is Not An Error When An Alternative Is Available". It seems I was being naive ;)Is there a way to determine at compile time whether a certain instantiation of a template function/class is possible? Am I missing something obvious here?Thanks![Edited by - Koen on February 26, 2008 11:07:53 AM]
  Not sure if boost::numeric_cast offers a similar facility, but std::numeric_limits offers an is_specialized static member that does what you want.Otherwise you can look at the boost source and do the same thing yourself, but that's not guaranteed to work for future releases obviously.  It appears at first glance, that right now they use is_arithmetic.;  This works using type traits and template specialisation if I have understood the problem domain correctly. It allows you to have just a single method (func())which will resolve to lexical or numeric cast at compile time. It relies on having the lexical cast reject types that are not convertable if they are not numeric. It would be nicer if you could do and/or type logic operations in the specialisation but i am not sure how you might do it in c++.#include <iostream>#include <string> #include <boost/lexical_cast.hpp>#include <boost/numeric/conversion/cast.hpp>#include <boost/type_traits.hpp>using namespace std; using namespace boost; using boost::numeric_cast;using namespace boost::type_traits;template<typename T, bool is_arith = boost::is_arithmetic<T>::value>struct Convert; template< typename T> struct Convert< T, true>{   int operator()( T v) { return numeric_cast< int>( v); }  };template< typename T> struct Convert< T, false>{   int operator()( T v) { return lexical_cast< int>( v); }  };class A{public:   template< class T>    int func( T value)   { return  Convert< T>()( value);}};main(){   A  a;    cout << "int    func " << a.func( 123) << endl;    cout << "float  func " << a.func( 123.f) << endl;cout << "char * func " << a.func( "123") << endl;cout << "string func " << a.func( string( "123")) << endl;   // cout << "something else " << a.func( int *) << endl;  // will fail on compilation};Quote:Original post by mfawcettNot sure if boost::numeric_cast offers a similar facility, but std::numeric_limits offers an is_specialized static member that does what you want.Yep, that would work. Unfortunately it doesn't exist for numeric_cast and lexical_cast (or at least, not as far as I can see...).A second solution I tried also doesn't work:template<class TDestination, class TSource>class CanDoNumericCast  {  private:   typedef char Yes;    class No {char dummy[2];};    template<class TDestination, class TSource>    static Yes Test(boost::numeric::converter<TDestination, TSource> test = boost::numeric::converter<TDestination, TSource>());    template<class TDestination, class TSource>    static No Test(...);  public:    enum { value = sizeof(Test<TDestination,TSource>()) == sizeof(Yes) };  };If you instantiate this with std::string and double, the compiler still sets 'value' to true. So when matching the first static Test, it doesn't care if converter<std::string, double> can compile. I guess I'll have to live with the difference between matching and compiling.It would still be a useful tool though :)Quote:Original post by chairthrowerThis works using type traits and template specialisation if I have understood the problem domain correctly. It allows you to have just a single method (func())which will resolve to lexical or numeric cast at compile time. It relies on having the lexical cast reject types that are not convertable if they are not numeric. It would be nicer if you could do and/or type logic operations in the specialisation but i am not sure how you might do it in c++.*** Source Snippet Removed ***That's how I have implemented it now. It still feels a bit wrong, because the is_arithmetic implementation could change regardless of how the casts are implemented.Anyway, thanks for your replies!;Quote:Original post by KoenThat's how I have implemented it now. It still feels a bit wrong, because the is_arithmetic implementation could change regardless of how the casts are implemented.Right, and not only that (like I mentioned in my first post), the boost implementations aren't necessarily going to remain restricted by is_arithmetic in future releases.  You are relying on implementation details.