
Starting to hack with boost libraries I found myself more and more stumbling across a big brick of C++ language, i.e. SFINAE works on types only, not on expressions. If an expression is ill formed there's no SFINAE around that will avoid you a barfing compiler. Looking at C++0x I failed to see a future improvement in that direction, also 'concepts' that will be quite new, apart from helping in decoding error messages (and this is a BIG help I would add), does not immediately seem to extend the language in that direction. For what I have understood 'refinements' are more or less similar to tag dispatching so does not seem to open completely new gates (of course this is just a first look opinion, it means that is not immediately visible to me how to use concepts to add to what you already can do using a more verbose approach, not that for sure it does not exist a way). I would like to ask you if someone has never dreamed of something like try well_formed { .... your code here... } catch { .... fall back code in case former is not compilable... }; I would think this would be an extension that greatly will open new gates to C++. Just to be clear, I'm not advocating to introduce something like the above, just to ask if a discussion around the above lines have never occurred in the C++ community. Thanks Marco

Marco Costalba wrote:
I would like to ask you if someone has never dreamed of something like
try well_formed {
.... your code here...
} catch {
.... fall back code in case former is not compilable...
};
I think Concepts somehow help here. By using a concept to check whether a type has given member functions or operators with given signatures, and overloading the piece of code without a concept to be the fallback code, you get similar things. Also, you could provide some compile-time reflection to check whether an expression is valid or not.
I would think this would be an extension that greatly will open new gates to C++.
Such as duck typing?

On 10/16/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
Also, you could provide some compile-time reflection to check whether an expression is valid or not.
Problem I found is that compile-time info sometime is not enough. As example if you have something like this: template<int n, typename arg> void dispatch_on_value(std::string const& s, arg const& a) { if ( s == some_string(n) ) /* calls member foo() on the class returned by get_a_class */ return get_a_class<n>().foo(a); return dispatch_on_value<n-1>(s, a); // try with next one } In this simple example template function get_a_class<int>() returns different classes according to parameter <int>. On the returned classes member foo() with argument 'a' is called. The problem is that not all the classes returned by get_a_class<int> could have a member foo(), or also if they have, signature of foo() could be different for each class, so that foo(a) could be ill formed for some of them. What is sure, because of perhaps application knowledge, is that the for the value 'n' for which 's == some_string(n)' the code is well formed, i.e. get_a_class<n>().foo(a) is compilable. In this case compile time info is clearly not enough because calling the good foo(a) requires run-time knowledge: the value of string 's' The above code will always give compile error also if the path that leads to calling get_a_class<int>().foo(a) is taken only for the correct case. The ill formed functions are never called because 'if' condition is never met for them, but this is unknown to the compiler that raises an error in any case. Rewriting the above with the new fancyness: template<int n, typename arg> void dispatch_on_value(std::string const& s, arg const& a) { if ( s == some_string(n) ) try well_formed { return get_a_class<n>().foo(a); } catch { assert(false); // runtime assert, NOT compile time! }; return dispatch_on_value<n-1>(s, a); // try with next one } IMHO it is both safe and useful in this case as probably in other cases where you need both compile time + run-time info to choose among a possible set of instantiations. Thanks Marco

Marco Costalba wrote:
Problem I found is that compile-time info sometime is not enough.
As example if you have something like this:
template<int n, typename arg> void dispatch_on_value(std::string const& s, arg const& a) { if ( s == some_string(n) )
/* calls member foo() on the class returned by get_a_class */ return get_a_class<n>().foo(a);
return dispatch_on_value<n-1>(s, a); // try with next one }
In this simple example template function get_a_class<int>() returns different classes according to parameter <int>.
On the returned classes member foo() with argument 'a' is called.
The problem is that not all the classes returned by get_a_class<int> could have a member foo(), or also if they have, signature of foo() could be different for each class, so that foo(a) could be ill formed for some of them.
Then, as I said, you could provide compile-time information to know what are all the members of a class and all their signatures. template<typename T> struct reflection { }; template<> struct reflection<YourClass> { typedef boost::mpl::map< boost::mpl::pair< boost::mpl::vector_c<char, 'f', 'o', 'o'>, boost::mpl::vector< boost::mpl::pair< return_type, boost::mpl::vector<> /* argument types */ > boost::mpl::pair< // another overload another_return_type, boost::mpl::vector<> /* other argument types */ > > > type; }; Then you write a meta-function to check whether the class has a member function with the corresponding name and signature and branch with SFINAE. Of course here the reflection format is quite primitive. It should be improved to represent all of member variables, member functions, typedefs, static variables, static functions. Also I don't really see how to expose template signatures.

On 10/17/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
Of course here the reflection format is quite primitive. It should be improved to represent all of member variables, member functions, typedefs, static variables, static functions. Also I don't really see how to expose template signatures.
And it doesn't work with implicit conversions: what if you pass a const char* "test" as argument for a std::string ? It would be erroneusly rejected ? Moreover I'm not sure it is valid for the general case of ill formed template expressions due to run-time variables values. Anyway thanks for your code, I didn't know that trick ! Marco

Marco Costalba wrote:
And it doesn't work with implicit conversions: what if you pass a const char* "test" as argument for a std::string ? It would be erroneusly rejected ?
Use the is_convertible type_traits to know whether your type is convertible to the requested argument type.
Moreover I'm not sure it is valid for the general case of ill formed template expressions due to run-time variables values.
In C++, you can't call a type-specific operator or member if you don't know the type of the variable at compile-time. So I really don't understand what you mean.

Looking at C++0x I failed to see a future improvement in that direction, also 'concepts' that will be quite new, apart from helping in decoding error messages (and this is a BIG help I would add), does not immediately seem to extend the language in that direction.
For what I have understood 'refinements' are more or less similar to tag dispatching so does not seem to open completely new gates (of course this is just a first look opinion, it means that is not immediately visible to me how to use concepts to add to what you already can do using a more verbose approach, not that for sure it does not exist a way).
They do all that and more :) Concepts are actually derived from the old STL documentation - a way of expressing requirements (and guarantees via axioms) on types in template code. So one way to use them is to require that your template arguments types have specific interfaces. The other way is to use them to /provide/ those interfaces for types that don't support them (via concept_maps). Think of them as adapter classes. This means you could (theoretically) take the old CArrary from MFC, and provide a concept_map that makes it look like a std::vector, and be able to use that as the internals of a std::stack. I'm not saying it's a good idea, but you can probably do it.
I would like to ask you if someone has never dreamed of something like
try well_formed {
.... your code here...
} catch {
.... fall back code in case former is not compilable...
};
I would think this would be an extension that greatly will open new gates to C++.
I think there are probably too many places where a compiler can fail. Try to find all of the broken language aspects in Boost.Config, and then generalize this solution to all of those. You'd end up having this construct around, well, most of your program. The only viable solution to this is the preprocessor - it's ugly, but it's been effective for 30 years, and I don't see it going away any time soon :) Andrew Sutton asutton@cs.kent.edu

Andrew Sutton wrote:
I would like to ask you if someone has never dreamed of something like
try well_formed {
.... your code here...
} catch {
.... fall back code in case former is not compilable...
};
I would think this would be an extension that greatly will open new gates to C++.
I think there are probably too many places where a compiler can fail. Try to find all of the broken language aspects in Boost.Config, and then generalize this solution to all of those. You'd end up having this construct around, well, most of your program. The only viable solution to this is the preprocessor - it's ugly, but it's been effective for 30 years, and I don't see it going away any time soon :)
Preprocessor doesn't always save you. I had couple of times when I needed to detect availability of a non-member type or function - mostly, for portability reasons. This is where scary things like above or __if_exists/__if_not_exists MSVC extension may come handy. I wonder if concepts are able to do that.

on Tue Oct 16 2007, "Marco Costalba" <mcostalba-AT-gmail.com> wrote:
Starting to hack with boost libraries I found myself more and more stumbling across a big brick of C++ language, i.e. SFINAE works on types only, not on expressions.
If an expression is ill formed there's no SFINAE around that will avoid you a barfing compiler.
Looking at C++0x I failed to see a future improvement in that direction, also 'concepts' that will be quite new, apart from helping in decoding error messages (and this is a BIG help I would add), does not immediately seem to extend the language in that direction.
For what I have understood 'refinements' are more or less similar to tag dispatching so does not seem to open completely new gates (of course this is just a first look opinion, it means that is not immediately visible to me how to use concepts to add to what you already can do using a more verbose approach, not that for sure it does not exist a way).
I would like to ask you if someone has never dreamed of something like
try well_formed {
.... your code here...
} catch {
.... fall back code in case former is not compilable...
};
I would think this would be an extension that greatly will open new gates to C++.
Just to be clear, I'm not advocating to introduce something like the above, just to ask if a discussion around the above lines have never occurred in the C++ community.
Yes, the compiler vendors have a really hard time seeing how such a feature could be implemented. The problem is that they have data structures such as symbol tables that are updated as code is parsed, and there's no way to roll them back to the state they were in before the try block if the code turns out to be ill-formed. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
on Tue Oct 16 2007, "Marco Costalba" <mcostalba-AT-gmail.com> wrote:
I would like to ask you if someone has never dreamed of something like
try well_formed {
.... your code here...
} catch {
.... fall back code in case former is not compilable...
};
I would think this would be an extension that greatly will open new gates to C++.
Yes, the compiler vendors have a really hard time seeing how such a feature could be implemented. The problem is that they have data structures such as symbol tables that are updated as code is parsed, and there's no way to roll them back to the state they were in before the try block if the code turns out to be ill-formed.
OK, that has got to be one of the lamest excuses I've heard from compiler vendors so far. All the compilers I've written have had some form of stacked symbol tables for the sole point of implementing scopes. And this is just another scope use case. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - grafikrobot/yahoo

on Wed Oct 17 2007, Rene Rivera <grafikrobot-AT-gmail.com> wrote:
David Abrahams wrote:
on Tue Oct 16 2007, "Marco Costalba" <mcostalba-AT-gmail.com> wrote:
I would like to ask you if someone has never dreamed of something like
try well_formed {
.... your code here...
} catch {
.... fall back code in case former is not compilable...
};
I would think this would be an extension that greatly will open new gates to C++.
Yes, the compiler vendors have a really hard time seeing how such a feature could be implemented. The problem is that they have data structures such as symbol tables that are updated as code is parsed, and there's no way to roll them back to the state they were in before the try block if the code turns out to be ill-formed.
OK, that has got to be one of the lamest excuses I've heard from compiler vendors so far. All the compilers I've written have had some form of stacked symbol tables for the sole point of implementing scopes. And this is just another scope use case.
No, it's not. You have to be able to undo template instantiations and other permanent state changes that can't be stacked. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Ok, never coded a compiler, and never probably will, I program C++ but I'm not an expert, anyway from the outside here are my 2 cents: The code mixes runtime decisions with compile time checks and that does not add up, no way that can be implemented on the current standard. About the given problem, the solution is using dynamic polymorphism directly: all classes returned by get_class<n> match an interface defining virtual void foo( T const& ) for each possible T, possible implementation being assert(false) in the base class. Then if all get_class<n> resulting classes inherit from that base class the code will compile and solve the problem at hand. I am now assuming that the code was just an example to represent the feature that is being requested. To support that feature, the compiler must add code that checks at runtime for the existence of foo( specific_T const& ) and if it does not find it ends execution. This code should be added in dispatch_on_value and must check RTTI from the result of get_class<n>, which in the example is easy to spot, but it is not hard to consider the same 'try wellformed { ... }' structure with many more lines, and the compiler must decide for which parts of the code the extra runtime check must be generated. Should it be generated only for objects returned from templated functions/template methods, or is the softer type check also required for all the code? If it is for all the code, do all binaries have the appropiate RTTI info? Can we not link against C dynamic libs? Libs generated with other compilers? With other compiler options? Then again, I can assume that easing the programming of the compiler is just an excuse (I am not going to code the compiler anyway! :P), but then...
From the programmers standpoint that feature will lift some of the type safety requirements. Suddenly if something is surrounded in such a block, type safety is not checked there until runtime, errors that are now detected during compilation creep into binaries and can only be found through extensive testing of all execution flows that go through the block (all cases for which 's==some_string(n)' in the example, but quite harder task on other code) and the error messages will probably be quite less explicit --I already have problems following compile time errors using boost libs, I surely don't want to debug with just the output of a runtime (possibly stripped, optimized) binary. Here's your new gun, go shoot yourself.
My opinion on this subject is that the implications of the extension to the standard seem to help with an specific use case, at the cost of quite some work on the compiler, heavier binaries and harder debugging for the programmer. If you add to it that it is not an 'enabling' technology --it does not solve any now-unsolvable problem, AFAIK. I would not be optimistic in the acceptance of such a feature. Then again, I am no expert. David P.S. Please don't anyone get offended, I am probably wrong on some of the specifics (some of questions at the end of first paragraph?), but I do believe on the whole idea. On 10/18/07, David Abrahams <dave@boost-consulting.com> wrote:
on Wed Oct 17 2007, Rene Rivera <grafikrobot-AT-gmail.com> wrote:
David Abrahams wrote:
on Tue Oct 16 2007, "Marco Costalba" <mcostalba-AT-gmail.com> wrote:
I would like to ask you if someone has never dreamed of something like
try well_formed {
.... your code here...
} catch {
.... fall back code in case former is not compilable...
};
I would think this would be an extension that greatly will open new gates to C++.
Yes, the compiler vendors have a really hard time seeing how such a feature could be implemented. The problem is that they have data structures such as symbol tables that are updated as code is parsed, and there's no way to roll them back to the state they were in before the try block if the code turns out to be ill-formed.
OK, that has got to be one of the lamest excuses I've heard from compiler vendors so far. All the compilers I've written have had some form of stacked symbol tables for the sole point of implementing scopes. And this is just another scope use case.
No, it's not. You have to be able to undo template instantiations and other permanent state changes that can't be stacked.
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

David Rodríguez Ibeas wrote:
all classes returned by get_class<n> match an interface defining virtual void foo( T const& ) for each possible T I'm fuzzy on the past of this thread, but I should point out that member templates can't be virtual. The base class would have to change in response to a template instantiation on the derived class. So if "each possible T" means "each from the set you need", that's fine. But not a template.
Sebastian Redl

On 10/19/07, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
David Rodríguez Ibeas wrote:
all classes returned by get_class<n> match an interface defining virtual void foo( T const& ) for each possible T I'm fuzzy on the past of this thread, but I should point out that member templates can't be virtual. The base class would have to change in response to a template instantiation on the derived class. So if "each possible T" means "each from the set you need", that's fine. But not a template.
Sebastian Redl
Thanks for the correction. I was not sure on that! :) My first idea was just to type the (incorrect) option: template <typename T> virtual void foo( T&... ), and doubting on whether that was correct I changed it into the version above version avoiding to mention the template part. What about with template compilation model with template instantiations for 'each from the set you need'? Do compilers (which?) support template compilation? I tried once with g++ but did not succeed. David

Feel free to ignore this as it might be going off-topic... David Abrahams wrote:
on Wed Oct 17 2007, Rene Rivera <grafikrobot-AT-gmail.com> wrote:
David Abrahams wrote:
Yes, the compiler vendors have a really hard time seeing how such a feature could be implemented. The problem is that they have data structures such as symbol tables that are updated as code is parsed, and there's no way to roll them back to the state they were in before the try block if the code turns out to be ill-formed.
OK, that has got to be one of the lamest excuses I've heard from compiler vendors so far. All the compilers I've written have had some form of stacked symbol tables for the sole point of implementing scopes. And this is just another scope use case.
No, it's not.
I guess that depends on your definition of scope.
You have to be able to undo template instantiations and other permanent state changes that can't be stacked.
Template instantiations go into the symbol table, like everything else. What makes them different that they can't be undone? What other permanent state changes are there that don't involve the symbol table? -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - grafikrobot/yahoo

on Thu Oct 18 2007, Rene Rivera <grafikrobot-AT-gmail.com> wrote:
Feel free to ignore this as it might be going off-topic...
David Abrahams wrote:
on Wed Oct 17 2007, Rene Rivera <grafikrobot-AT-gmail.com> wrote:
David Abrahams wrote:
Yes, the compiler vendors have a really hard time seeing how such a feature could be implemented. The problem is that they have data structures such as symbol tables that are updated as code is parsed, and there's no way to roll them back to the state they were in before the try block if the code turns out to be ill-formed.
OK, that has got to be one of the lamest excuses I've heard from compiler vendors so far. All the compilers I've written have had some form of stacked symbol tables for the sole point of implementing scopes. And this is just another scope use case.
No, it's not.
I guess that depends on your definition of scope.
You have to be able to undo template instantiations and other permanent state changes that can't be stacked.
Template instantiations go into the symbol table, like everything else. What makes them different that they can't be undone? What other permanent state changes are there that don't involve the symbol table?
Maybe you should ask the implementors. I'm sure the EDG guys and the GCC maintainers would be happy to explain it to you. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On 10/17/07, David Abrahams <dave@boost-consulting.com> wrote:
Just to be clear, I'm not advocating to introduce something like the above, just to ask if a discussion around the above lines have never occurred in the C++ community.
Yes, the compiler vendors have a really hard time seeing how such a feature could be implemented. The problem is that they have data structures such as symbol tables that are updated as code is parsed, and there's no way to roll them back to the state they were in before the try block if the code turns out to be ill-formed.
Thanks for your answer. I'm not a compiler expert so proably the immediately idea of reparse the whole file in such cases is just very naive. And so surely is the idea to save the compiler state at the beginning of the try block. Anyhow, could you please tell me if does exsist a poposal somewhere about this matter that has been formally discussed and rejected or the talks were informal? Thanks Marco

On Oct 16, 2007, at 5:58 AM, Marco Costalba wrote:
Starting to hack with boost libraries I found myself more and more stumbling across a big brick of C++ language, i.e. SFINAE works on types only, not on expressions.
If an expression is ill formed there's no SFINAE around that will avoid you a barfing compiler.
This issue has been actively discussed in the C++ committee. You can track it's progress via core issue 339 on the Core Issues list, which is here: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#339 At the very bottom of the issue text, there is a note that describes the latest view on the matter. The resolution we're likely to get is that SFINAE will be extended to support expressions. There are still cases that will cause "hard" failures (not SFINAE failures), for example if one ends up trying to instantiate a class template inside a sizeof() expression and that instantiation fails.
Looking at C++0x I failed to see a future improvement in that direction, also 'concepts' that will be quite new, apart from helping in decoding error messages (and this is a BIG help I would add), does not immediately seem to extend the language in that direction.
Concepts are actually quite a big improvement in this area. Mathias Gaunard mentioned how the use of concepts along with (concept-based) overloading can solve the kind of problem you're describing, where you need to query the properties of a type and decide between two alternatives. Concepts allow you to describe the properties of types via a set of requirements. For example, here's a short concept that describes some properties of numeric types: concept Numeric<typename T> { T::T(T const &); T operator+(T, T); T operator-(T, T); T operator*(T, T); T operator/(T, T); T operator-(T); T operator+(T); } Many types meet the requirements of this concept: int, float, double, and a user-defined bigint, for example, would all have the necessary copy constructor and arithmetic operations. Using concepts, we can write generic algorithms as "constrained" templates, e.g., template<typename T> requires Numeric<T> T twice(T x) { return x + x; } Now, for integral types (int, long, etc.), we would really rather implement twice() with a simple shift operation. So, we first define a new concept that captures the notion of an integral type: concept Integral<typename T> : Numeric< T> { T operator<<(T, int); T operator>>(T, int); } Integral is a *refinement* of Numeric, meaning that it inherits all of the requirements of the Numeric concept. So, to be an integral type on needs to have all of the operations from Numeric (+, -, *, /, etc.) and from Integral (<<, >>). Every type that is Integral is also Numeric. Using the Integral concept, we can write an overload of the twice() function: template<typename T> requires Integral<T> T twice(T x) { return x << 1; } Now, when a user calls twice() with a particular type, the compiler will find both overloads. If the type is Numeric, the first overload works and will be chosen; if the type is Integral, both overloads work but the second (more specific, more efficient) overload will be chosen. So instead of some kind of "try_compile" block, you just write down the requirements you need to check (e.g., whether the type is integral, whether it has a << operator, etc.) as a concept, and then write two overloads: one if that property is satisfied, one if that property is not satisfied. - Doug

On 10/18/07, Doug Gregor <dgregor@osl.iu.edu> wrote:
On Oct 16, 2007, at 5:58 AM, Marco Costalba wrote:
Starting to hack with boost libraries I found myself more and more stumbling across a big brick of C++ language, i.e. SFINAE works on types only, not on expressions.
If an expression is ill formed there's no SFINAE around that will avoid you a barfing compiler.
This issue has been actively discussed in the C++ committee. You can track it's progress via core issue 339 on the Core Issues list, which is here:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#339
At the very bottom of the issue text, there is a note that describes the latest view on the matter. The resolution we're likely to get is that SFINAE will be extended to support expressions. There are still cases that will cause "hard" failures (not SFINAE failures), for example if one ends up trying to instantiate a class template inside a sizeof() expression and that instantiation fails.
From above cited document:
"We decided it's easier to write the definition by listing the errors that are not treated as SFINAE failures, and the list we came up with is as follows: 1-errors that occur while processing some entity external to the expression, e.g., an instantiation of a template or the generation of the definition of an implicitly-declared copy constructor" This limitation seems quite important. As example in the code I posted in this thread: template<int n, typename arg> void dispatch_on_value(std::string const& s, arg const& a) { if ( s == some_string(n) ) /* calls member foo() on the class returned by get_a_class */ return get_a_class<n>().foo(a); return dispatch_on_value<n-1>(s, a); // try with next one } I could think to use sizeof as a specialization somewhere to filter out invalid functions, something like: sizeof(get_a_class<n>().foo(arg())) But, if I have read correctly the proposed change, this would result in being still considered an error, not under SFINAE case. IMHO closing the doors to instantiation of a class template inside a sizeof() expression could cut away a good number of possible cases, also not easy to foressen ones (i.e. from where language 'progress' normally comes from). In my case, if you have a compile time set of functions/classes and you want to choose at run-time one among them using a run-time entity (variable, arguments values, etc..) a possible way would be to create at compile time a chain of all the instantations of your set, linked with recursion, then at run-time return from the recursion chain at the point your run-time requirements are met. But this works only if at compile-time it would be possible to discard the ill-formed ones when instantiating the recursive chain. Am I missing something? Thanks Marco

On Oct 21, 2007, at 12:29 AM, Marco Costalba wrote:
"We decided it's easier to write the definition by listing the errors that are not treated as SFINAE failures, and the list we came up with is as follows:
1-errors that occur while processing some entity external to the expression, e.g., an instantiation of a template or the generation of the definition of an implicitly-declared copy constructor"
This limitation seems quite important. As example in the code I posted in this thread:
template<int n, typename arg> void dispatch_on_value(std::string const& s, arg const& a) { if ( s == some_string(n) )
/* calls member foo() on the class returned by get_a_class */ return get_a_class<n>().foo(a);
return dispatch_on_value<n-1>(s, a); // try with next one }
I could think to use sizeof as a specialization somewhere to filter out invalid functions, something like:
sizeof(get_a_class<n>().foo(arg()))
But, if I have read correctly the proposed change, this would result in being still considered an error, not under SFINAE case.
If the instantiation of get_a_class<n> fails, this would be an error. However, if get_a_class<n> has no default constructor, has no function "foo", has no function "foo" that can take an "arg" parameter, has several functions "foo" that can take an "arg" parameter but nothing that is unambiguously the best overload, has a "foo" that is not a function, or if "arg" has no default constructor... it's a SFINAE case.
IMHO closing the doors to instantiation of a class template inside a sizeof() expression could cut away a good number of possible cases, also not easy to foressen ones (i.e. from where language 'progress' normally comes from).
Perhaps it does. However, extending SFINAE to cover instantiation of class templates is technically infeasible in today's C++ compilers. Instantiation of class templates causes many side effects in a typical compiler, altering various data structures along the way. Sure, it is conceivable that one could use a transaction-based approach to create a compiler that can roll back any operation, including instantiation... but it will not happen. The cost of changing an existing compiler to use this model is immense, and the payoff is tiny: a few C++ expert hackers will be able to do a little more. Compiler development is
In my case, if you have a compile time set of functions/classes and you want to choose at run-time one among them using a run-time entity (variable, arguments values, etc..) a possible way would be to create at compile time a chain of all the instantations of your set, linked with recursion, then at run-time return from the recursion chain at the point your run-time requirements are met.
You can use SFINAE at each step in the chain to determine whether that requirement is met.
Am I missing something?
There are two important points: 1) The resolution of core issue 339 gives us a *lot* more to work with in SFINAE cases. We can now easily detect whether various expressions are valid, which is a huge step forward for template metaprogramming. It also requires a non-trivial implementation effort for compiler vendors; I know, because I've implemented most of the resolution in GCC, which is by far the best prepared for this change. 2) Concepts are far better for solving this kind of problem than SFINAE ever will be. Most of the uses of various template tricks--- including SFINAE, tag dispatching, traits, concept checking, and archetypes---are hacks used to emulate the basic ideas of generic programming. Concepts express those ideas directly in code, simplifying their expression and integrating them with the compiler's type checker. - Doug
participants (10)
-
Andrew Sutton
-
Andrey Semashev
-
David Abrahams
-
David Rodríguez Ibeas
-
Doug Gregor
-
Douglas Gregor
-
Marco Costalba
-
Mathias Gaunard
-
Rene Rivera
-
Sebastian Redl