I came up with the following problem (code below):
template<class T>
void printname(const T& t){std::cout<<t<<std::endl;}
template<class T>
void applyfunc(const T& t, void (*f)(const T& )){(*f)(t);}
int main(){
const int a=1;
applyfunc(a,printname);
getchar();
return 0;
}
My problem is that it compiles with vc++8(VS2005), and GCC, CLang (on Ubuntu 12.04)
but fails to compile with vc++ 2008 express.
It seems to be legal code but I don't really get why.
If anyone could explain it I'd appreciate it.
Supposing it is legal, is there any way that something similar could be done with functors?
I assume you meant to use func for printname (or vice versa).
For what it's worth, I believe this code to be legal, and the fact that VS2008 (and also VS2010; I don't have VS2012 handy at the moment) rejects it looks like a compiler bug.
Re: something similar with functors - see if this does it for you:
#include <iostream>
struct printname {
template<class T>
void operator()(const T& t) { std::cout<<t<<std::endl; }
};
template<class T, class F>
void applyfunc(const T& t, F f) { f(t); }
int main(){
const int a=1;
applyfunc(a, printname());
return 0;
}
I am not sure as of whether the question is why it works in most compilers or why it fails in VS2008. If the question is the former, we can discuss a simplified version of this:
template <typename T>
void f(T const &) {}
void g(void (*fn)(std::string const&) {}
g(f); // compiles
void (*fn)(double const &) = f;
Pointers to functions are a bit special in the language, since the same name can refer to different overloads. When the name of a function is used in code, the compiler cannot determine which of the overloads is determined by itself, so it will use the target of the expression to determine this. In the case of g(f), since the g function takes a function of type void (std::string const&), it will resolve f to mean f<std::string>, while in the case of the initialization of fn the compiler will resolve to the specialization f<double>.
Note that this is a very commonly used feature of the language:
std::cout << std::endl;
The name std::endl refers to a template:
template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
The compiler sees that this is being called on the object std::cout, of type basic_ostream<char,char_traits<char>>, and that the only specialization that matches the call to operator<< is that where charT == char and traits == char_traits<char> and picks the correct specialization.
On Visual Studio 2010, the solution is easy yet subtle. You simply need to add <int> after printname in the line applyfunc(a,printname<int>);. The compiler needs help figuring out the template type to use.
#include <iostream>
struct printname
{
template<class T>
void operator()(const T& t)
{
std::cout << t << std::endl;
}
};
template<class T, class F>
void applyfunc(const T& t, F f)
{
f(t);
}
int main()
{
const int a=1;
applyfunc(a, printname<int>); // Add <int> here
return 0;
}
Related
I have a function which has an option parameter of type T.
template<typename T>
void foo( const T& t = T() )
{ t.stuff; }
This was all fine but I now have a scenario where T becomes void. In this case I expected a no-operation empty function. The only workable solution I have requires three separate declarations and I have many of these sort of methods:
template<typename T>
void foo( const T& t)
{ t.stuff; }
template<typename T>
inline void foo()
{ foo(T()); }
template<>
inline void foo<void>() {}
Ideally I hope there should be a more elegant solution to overload the 'Void' function without resorting to a 3rd declaration? Especially with new C++17 solving so many things these days! A more concise syntax that was shorter coudl be nice...
A simpler solution (in that there are only 2 overloads) would be something like this:
template<typename T>
void foo( const T& t = T() ) {
t.stuff;
}
template<typename T>
std::enable_if_t<std::is_void_v<T>>
foo() {}
// void foo(const T&); is the only viable overload for non-void T,
// since std::enable_if_t SFINAEs
// void foo(); is the only viable overload for void T,
// since const T& forms a reference to void
And this can be slightly shortened with alias templates since you use this pattern a lot:
template<typename T, typename TypeIfVoid = void>
using if_void = std::enable_if_t<std::is_void_v<T>, TypeIfVoid>;
template<typename T>
void foo(const T& t = T()) {
t.stuff;
}
template<typename T>
if_void<T> foo() {}
Two default template parameters will do it:
template<class T> using FallbackT = std::conditional_t<std::is_void_v<T>, int, T>;
template<class T = int&, class U = FallbackT<T>>
void foo(U const& t = U()) {
if constexpr (!std::is_void_v<T>)
t.stuff();
}
Example.
int& is the default for T so that compilation fails (default-constructing a reference at U()) if someone attempts to call foo() without either a template argument or an actual argument (try uncommenting it in the example).
I'm using int within FallbackT alias template since U just needs to be something that is default-constructible - this isn't visible to the user.
If you want to be fancy (and prevent misuse) you could add a variadic guard and use closure types:
template<
class T = decltype([]{})&,
class...,
class U = std::conditional_t<std::is_void_v<T>, decltype([]{}), T>>
void foo(U const& t = U()) {
if constexpr (!std::is_void_v<T>)
t.stuff();
}
Here, the variadic guard prevents specifying U explicitly, as e.g. foo<int, long>(); the closure types make it impossible for someone to call foo with those types by any other means - this is probably unnecessary.
Ideally I hope there should be a more elegant solution to overload the 'Void' function without resorting to a 3rd declaration? Especially with new C++17 solving so many things these days! A more concise syntax that was shorter coudl be nice...
Well... without a 3rd declaration, yes (you can use only one).
More elegant... it's question of tastes, I suppose.
More coincise syntax... well... almost the same, I suppose.
Anyway, I propose the following version, if constexpr and std::conditional_t based.
template <typename T,
typename U = std::conditional_t<std::is_same_v<T, void>,
int,
T>>
void foo (U const & u = U{})
{
if constexpr ( std::is_same_v<T, void> )
{ /* do nothing */ }
else
{ /* do u.stuff; */ }
}
In the following library functions f and g, I use std::span<const T> to remind the user of the library of the contract that f and g will not modify the contents of the span. The user of the library holds std::span<int> a, which is convertible to std::span<const int>. Hence, the user can call g(a) as expected. However, the user cannot call f(a), since f is a function template and a is not of the required type; conversions do not apply here. Can you see a (sane) way to have f take in std::span<const T> while still accepting std::span<T>?
#include <span>
void g(const std::span<const int>& a) {}
template <typename T>
void f(const std::span<const T>& a) {}
int main()
{
std::span<int> a;
// OK
g(a);
// No match
f(a);
// OK
f((std::span<const int>)a);
}
It is possible to add an overload like this:
template <typename T>
void f(const std::span<T>& a) {
return f((std::span<const T>)a);
}
But I'm not sure if I count this as sane, since then I would be writing these overloads to every function template which takes in std::span<const T>.
EDIT: Not the same case, but if f also happens to take in another parameter which mentions T, then one can do the following:
template <typename T> using NoDeduction = std::type_identity_t<T>;
template <typename T>
void f(NoDeduction<std::span<const T>> a, const T& b) {}
After which f(a, 1); works. This is a partial solution. The original problem still remains.
EDIT 2: I was wondering whether the above technique works also when we include span's compile-time size:
template <typename T, std::size_t N>
void f(const std::span<NoDeduction<const T>, N>& a, const T& b) {}
Gcc 10.1 compiles it, MSVC 16.6.2 and Clang 10.0.0 don't. I filed bug reports for both MSVC and Clang.
You can generalize your overload to be a utility like std::as_const:
template<class T>
std::span<const T> const_span(std::span<T> s) {return s;}
The caller then has to decorate their calls with mutable spans, but in so doing indicates to the reader that no modification is allowed.
Another, unconventional workaround would be to make your function be a class and use deduction guides:
template<class T>
struct f {
f(std::span<const T>);
// operator ReturnType();
};
template<class T> f(std::span<T>)->f<T>;
It’s debatable whether the interface describes the intent here.
It is unable to make the type conversion because it fails to deduce the type as f is a template.
If you want to write template function f that accepts various input types - you'd better write it as
template<typename Viewer>
void f(const Viewer& a){...}
If you want to work with span then you can implement it in two steps:
template<typename T>
void f_impl(std::span<const T> a){...}
template<typename Viewer>
void f(const Viewer& a)
{
f_impl(std::span<const typename Viewer::value_type>(a.data(),a.size()));
}
P.S. with span you should normally take copy of it instead of "const reference". This is more efficient.
I learned about c++17'sauto template parameters in the answer to this question. A coworker had informed me that they were supported on visual-studio-2017, but I seem to have been less than successful in my attempt to utilize this functionality. I've written this toy example to demonstrate my problem:
struct Foo {
int mem;
};
template <auto T>
decltype(T(Foo{})) bar(const Foo& param)
{
return T(param);
}
int func(const Foo& param) { return param.mem; }
int main() {
Foo myFoo{ 13 };
cout << bar<&func>(myFoo);
}
I believe this to be good code as it works fine on gcc In Visual Studio however I get this:
error C3533: a parameter cannot have a type that contains auto
I've ensured that my "C++ Language Standard" set to: "ISO C++ Latest Draft Standard (/std:c++latest)" but that doesn't seem to solve the problem. Visual Studio will support the pre-auto template parameter code which requires I pass the function type along with the function as template arguments: template <typename R, R(*T)(const Foo&)> R bar(const Foo& param) But this doesn't match the elegance of the auto template parameter.
Is there a way that I can either help Visual Studio compile the auto template code or manage similar elegance while still compiling on visual-studio-2017?
auto non-type template parameters were introduced only in VS 2017 version 15.7.0.
Templates that are designed to take any type as a non-type parameter can now use the auto keyword in the template parameter list. This allows instantiations to use any type instead of needing to determine and supply the type of template parameter at the point of instantiation.
Before that version they are not supported.
This MS help page states:
A method or template parameter cannot be declared with the auto keyword if the default /Zc:auto compiler option is in effect.
So you either turn off /Zc:auto or you can pass this function as parameter:
#include <iostream>
struct Foo {
int mem;
};
int func(const Foo& param) {
return param.mem;
}
template <class Func>
auto bar(const Foo& param, Func&& f) {
return f(param);
}
int main() {
Foo f { 42 };
std::cout << bar(f, func);
}
I have working code like this.
#include <iostream>
struct A{
template<typename T>
void foo(T val);
};
template<typename T> void A::foo(T val)
{
std::cout << val << std::endl;
}
// link template "against" int
template void A::foo(int val);
// #include header here
int main(){
A a;
a.foo(12);
}
Template is in separate CPP file, but linking works, because of explicit instantiation:
template void A::foo(int val);
Then I did some re-factoring, and code looks like this:
#include <iostream>
template<typename G>
struct A{
template<typename T>
void foo(T val);
};
template<typename G>
template<typename T> void A<G>::foo(T val)
{
std::cout << val << std::endl;
}
// link template "against" int - not working
//template<typename G>
//template void A<G>::foo(int val);
int main(){
A<float> a;
a.foo(12);
}
How can I "link" T=int, but keep G "unknown"?
It is called explicit instantiation.
You can't do this, because G is unknown and it is not a single type. It is rather a set of types.
You can not do this. To actually produce a code from a template (I guess that's what you call link), the compiler need to know all the template parameters.
So you are left with the standard options for template instantiation: either explicitly tell the compiler what T and G will be used, either let the compiler see full code for the template member wherever you use it (that is, include the code in header).
TL;DR you can't.
In your case I'd just specify the type you intend to use
template void A<float>::foo(int val);
or (rather bulky) explicitly instantiate all the types G could be used for.
There is no way you can explicitly instantiate the template if G cannot be deduced.
Notice that linking works not because this syntax is a linker command but because your compiler is producing code that is later found at link-time. See more here
I want to do something like
template <typename T>
void foo(const T& t) {
IF bar(t) would compile
bar(t);
ELSE
baz(t);
}
I thought that something using enable_if would do the job here, splitting up foo into two pieces, but I can't seem to work out the details. What's the simplest way of achieving this?
There are two lookups that are done for the name bar. One is the unqualified lookup at the definition context of foo. The other is argument dependent lookup at each instantiation context (but the result of the lookup at each instantiation context is not allowed to change behavior between two different instantiation contexts).
To get the desired behavior, you could go and define a fallback function in a fallback namespace that returns some unique type
namespace fallback {
// sizeof > 1
struct flag { char c[2]; };
flag bar(...);
}
The bar function will be called if nothing else matches because the ellipsis has worst conversion cost. Now, include that candidates into your function by a using directive of fallback, so that fallback::bar is included as candidate into the call to bar.
Now, to see whether a call to bar resolves to your function, you will call it, and check whether the return type is flag. The return type of an otherwise chosen function could be void, so you have to do some comma operator tricks to get around that.
namespace fallback {
int operator,(flag, flag);
// map everything else to void
template<typename T>
void operator,(flag, T const&);
// sizeof 1
char operator,(int, flag);
}
If our function was selected then the comma operator invocation will return a reference to int. If not or if the selected function returned void, then the invocation returns void in turn. Then the next invocation with flag as second argument will return a type that has sizeof 1 if our fallback was selected, and a sizeof greater 1 (the built-in comma operator will be used because void is in the mix) if something else was selected.
We compare the sizeof and delegate to a struct.
template<bool>
struct foo_impl;
/* bar available */
template<>
struct foo_impl<true> {
template<typename T>
static void foo(T const &t) {
bar(t);
}
};
/* bar not available */
template<>
struct foo_impl<false> {
template<typename T>
static void foo(T const&) {
std::cout << "not available, calling baz...";
}
};
template <typename T>
void foo(const T& t) {
using namespace fallback;
foo_impl<sizeof (fallback::flag(), bar(t), fallback::flag()) != 1>
::foo(t);
}
This solution is ambiguous if the existing function has an ellipsis too. But that seems to be rather unlikely. Test using the fallback:
struct C { };
int main() {
// => "not available, calling baz..."
foo(C());
}
And if a candidate is found using argument dependent lookup
struct C { };
void bar(C) {
std::cout << "called!";
}
int main() {
// => "called!"
foo(C());
}
To test unqualified lookup at definition context, let's define the following function above foo_impl and foo (put the foo_impl template above foo, so they have both the same definition context)
void bar(double d) {
std::cout << "bar(double) called!";
}
// ... foo template ...
int main() {
// => "bar(double) called!"
foo(12);
}
litb has given you a very good answer. However, I wonder whether, given more context, we couldn't come up with something that's less generic, but also less, um, elaborate?
For example, what types can be T? Anything? A few types? A very restricted set which you have control over? Some classes you design in conjunction with the function foo? Given the latter, you could simple put something like
typedef boolean<true> has_bar_func;
into the types and then switch to different foo overloads based on that:
template <typename T>
void foo_impl(const T& t, boolean<true> /*has_bar_func*/);
template <typename T>
void foo_impl(const T& t, boolean<false> /*has_bar_func*/);
template <typename T>
void foo(const T& t) {
foo_impl( t, typename T::has_bar_func() );
}
Also, can the bar/baz function have just about any signature, is there a somewhat restricted set, or is there just one valid signature? If the latter, litb's (excellent) fallback idea, in conjunction with a meta-function employing sizeof might be a bit simpler. But this I haven't explored, so it's just a thought.
I think litb's solution works, but is overly complex. The reason is that he's introducing a function fallback::bar(...) which acts as a "function of last resort", and then goes to great lengths NOT to call it. Why? It seems we have a perfect behavior for it:
namespace fallback {
template<typename T>
inline void bar(T const& t, ...)
{
baz(t);
}
}
template<typename T>
void foo(T const& t)
{
using namespace fallback;
bar(t);
}
But as I indicated in a comment to litb's original post, there are many reasons why bar(t) could fail to compile, and I'm not certain this solution handles the same cases. It certainly will fail on a private bar::bar(T t)
If you're willing to limit yourself to Visual C++, you can use the __if_exists and __if_not_exists statements.
Handy in a pinch, but platform specific.
EDIT: I spoke too soon! litb's answer shows how this can actually be done (at the possible cost of your sanity... :-P)
Unfortunately I think the general case of checking "would this compile" is out of reach of function template argument deduction + SFINAE, which is the usual trick for this stuff. I think the best you can do is to create a "backup" function template:
template <typename T>
void bar(T t) { // "Backup" bar() template
baz(t);
}
And then change foo() to simply:
template <typename T>
void foo(const T& t) {
bar(t);
}
This will work for most cases. Because the bar() template's parameter type is T, it will be deemed "less specialised" when compared with any other function or function template named bar() and will therefore cede priority to that pre-existing function or function template during overload resolution. Except that:
If the pre-existing bar() is itself a function template taking a template parameter of type T, an ambiguity will arise because neither template is more specialised than the other, and the compiler will complain.
Implicit conversions also won't work, and will lead to hard-to-diagnose problems: Suppose there is a pre-existing bar(long) but foo(123) is called. In this case, the compiler will quietly choose to instantiate the "backup" bar() template with T = int instead of performing the int->long promotion, even though the latter would have compiled and worked fine!
In short: there's no easy, complete solution, and I'm pretty sure there's not even a tricky-as-hell, complete solution. :(
//default
//////////////////////////////////////////
template <class T>
void foo(const T& t){
baz(t);
}
//specializations
//////////////////////////////////////////
template <>
void foo(const specialization_1& t){
bar(t);
}
....
template <>
void foo(const specialization_n& t){
bar(t);
}
Are you not able to use full specialisation here (or overloading) on foo. By say having the function template call bar but for certain types fully specialise it to call baz?