I have two function templates A and B. I define A and then B in the same file. Now I would like to call B in A. How can I realize this? Normal function prototype doesn't work in this case. (Please assume you cannot change the order of A and B or split files.)
#include <iostream>
template <class Type>
Type A(Type x) {
return 2 * B(x);
}
template <class Type>
Type B(Type x) {
return 3 * x;
}
int main() {
int x = 3;
std::cout << A(x) << "\n"; //=> ERROR
}
ERROR from g++:
test.cpp: In instantiation of ‘Type A(Type) [with Type = int]’:
test.cpp:40:21: required from here
test.cpp:29:17: error: ‘B’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
return 2 * B(x);
~^~~
test.cpp:33:6: note: ‘template<class Type> Type B(Type)’ declared here, later in the translation unit
Type B(Type x) {
^
If by prototype you mean declaration, it certainly does work in this case!
You can declare a function template just fine:
#include <iostream>
// Non-defining declaration B
template <class Type>
Type B(Type x);
// Defining declaration A
template <class Type>
Type A(Type x) {
return 2 * B(x);
}
// Defining declaration B
template <class Type>
Type B(Type x) {
return 3 * x;
}
int main() {
int x = 3;
std::cout << A(x) << "\n"; //=> NO ERROR
}
(live demo)
Related
I learn the C++ template name binding and instantiation recently, and find the strange behavious in the following code.
#include <iostream>
using namespace std;
template <typename T>
int f(T a)
{
return g(a); // g() should be dependent name
}
struct C {};
int g(C c)
{
return 0;
}
int g(int i)
{
return i;
}
int main()
{
// Works!
int z = f(C{});
// Error: no declarations were found by argument-dependent lookup at the point of instantiation
//int z = f(10);
cout << z << endl;
return 0;
}
I think g(T) should be dependent name and int z = f(10) should work like int z = f(C{}). But gcc-6.3.0 complains:
g++ -g -o tmpl tmpl.cpp
tmpl.cpp: In instantiation of ‘int f(T) [with T = int]’:
tmpl.cpp:29:17: required from here
tmpl.cpp:8:13: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
return g(a);
~^~~
tmpl.cpp:18:5: note: ‘int g(int)’ declared here, later in the translation unit
int g(int i)
I'm trying to build up some code that wants to declare a local variable (say of type test, as shown below). Construction of that local variable should use a constructor that takes a special Tag argument if such a constructor exists, or the default constructor otherwise.
What we've been able to come up with is as follows, where we specialize to construct either a void argument or a Tag argument, but compilers don't like that:
#include <iostream>
using std::cout;
struct Tag { };
template <bool z>
struct helper {
using type = void;
};
template <>
struct helper<true> {
using type = Tag;
};
template <bool z>
static typename helper<z>::type get_arg() {
return typename helper<z>::type();
}
struct test {
test(void) { cout << "test(void)\n"; }
test(Tag x) { cout << "test(Tag)\n"; }
test(const test&) = delete;
test(test&&) = delete;
};
template <typename T>
void try_construct() {
// we would be selecting from one of these by template metaprogramming
T a{typename helper<false>::type()};
T b{typename helper<true>::type()};
T c{get_arg<false>()};
T d{get_arg<true>()};
// Then do stuff with the suitably-constructed instance of T
// . . .
}
int main(void) {
try_construct<test>();
return 0;
}
Compiler output:
$ g++ -std=c++11 -c foo.cpp
foo.cpp: In instantiation of 'void try_construct() [with T = test]':
foo.cpp:38:23: required from here
foo.cpp:30:37: error: no matching function for call to 'test::test(<brace-enclosed initializer list>)'
T a{typename helper<false>::type()};
^
foo.cpp:30:37: note: candidates are:
foo.cpp:22:3: note: test::test(Tag)
test(Tag x) { cout << "test(Tag)\n"; }
^
foo.cpp:22:3: note: no known conversion for argument 1 from 'void' to 'Tag'
foo.cpp:21:3: note: test::test()
test(void) { cout << "test(void)\n"; }
^
foo.cpp:21:3: note: candidate expects 0 arguments, 1 provided
foo.cpp:33:23: error: no matching function for call to 'test::test(<brace-enclosed initializer list>)'
T c{get_arg<false>()};
^
foo.cpp:33:23: note: candidates are:
foo.cpp:22:3: note: test::test(Tag)
test(Tag x) { cout << "test(Tag)\n"; }
^
foo.cpp:22:3: note: no known conversion for argument 1 from 'helper<false>::type {aka void}' to 'Tag'
foo.cpp:21:3: note: test::test()
test(void) { cout << "test(void)\n"; }
^
foo.cpp:21:3: note: candidate expects 0 arguments, 1 provided
We know how to test on the presence of the constructor, so I've left that our of the example. If that does end up being relevant in a solution taking a different approach, feel free to go that route.
Our ultimate goal is to require one of the default constructor or the Tag constructor, and neither of the copy or move constructors.
namespace details {
template<class T>
T maybe_tag_construct(std::true_type) {
return T(Tag{});
}
template<class T>
T maybe_tag_construct(std::false_type) {
return T();
}
}
template<class T>
T maybe_tag_construct() {
return details::maybe_tag_construct<T>( std::is_constructible<T, Tag>{} );
}
now auto t =maybe_tag_construct<test>(); constructs test from Tag iff it works.
It also does elided move construction before c++17, and in c++17 no move construction occurs.
In order to pass an instance of void around, you need the "regular void" proposal, which is on track for c++2a last I checked.
I think something along these lines works:
#include <type_traits>
template <typename T, bool B = std::is_constructible<Tag, T>> struct H;
template <typename T>
struct H<T, false> {
T t;
H() : t() {}
};
template <typename T>
struct H<T, true> {
T t;
H() : t(Tag) {}
};
try_construct() {
H<T> h;
h.t;
}
Trying to propose a solution to another question, I bumped (again) my nose against code that compile and work with clang++ (3.5) but give compilation error with g++ (4.9.2)
The following is a simplified minimal (I hope) example
#include <iostream>
class foo;
template <std::size_t>
struct bar;
template <>
struct bar<0U>
{ static void baz (foo const & f); };
class foo
{
int i = 42;
template <std::size_t I>
friend void bar<I>::baz (foo const &);
};
void bar<0U>::baz (foo const & f)
{ std::cout << f.i << std::endl; }
int main()
{
foo f;
bar<0U>::baz(f);
}
The error from my g++ is
test_114-98,11,14,clang.cpp:18:41: error: member ‘void bar<<anonymous> >::baz(const foo&)’ declared as friend before type ‘bar<<anonymous> >’ defined
friend void bar<I>::baz (foo const &);
^
test_114-98,11,14,clang.cpp: In static member function ‘static void bar<0ul>::baz(const foo&)’:
test_114-98,11,14,clang.cpp:15:13: error: ‘int foo::i’ is private
int i = 42;
^
test_114-98,11,14,clang.cpp:22:19: error: within this context
{ std::cout << f.i << std::endl; }
^
My question, as usual, is: who's right and who's wrong.
Is it possible to pass a class method as a parameter to a template? For example:
template<typename T, void(T::*TFun)()>
void call(T* x) {
x->TFun();
}
struct Y {
void foo();
};
int main() {
Y y;
call<Y,&Y::foo>(&y); // should be the equivalent of y.foo()
}
If I try compiling the above, I get:
main.cpp: In instantiation of void call(T*) [with T = Y; void (T::* TFun)() = &Y::foo]:
main.cpp:12:23: required from here
main.cpp:4:5: error: struct Y has no member named TFun
x->TFun();
^
Is this possible and if so, what's the syntax?
That's not how you refer to a pointer-to-member. You need to dereference it first:
(x->*TFun)();
I used parenthesis do deal with operator precedence issues. TFun will be dereferenced before it is called.
The following code does not compile with G++ (although I believe it should):
#include <iostream>
template <unsigned N>
struct foo_traits {
typedef const char ArrayArg[N];
typedef int Function (ArrayArg *);
};
template <unsigned N>
int foo (typename foo_traits<N>::Function *ptr) {
return ptr(&"good");
}
int bar (const char (*x)[5]) {
std::cout << *x << "\n";
return 0;
}
int main ()
{
return foo(bar);
}
I checked this with GCC 4.4 through 4.7, and I get a template argument deduction failure. With 4.7.1:
prog.cpp: In function ‘int main()’:
prog.cpp:21:19: error: no matching function for call to ‘foo(int (&)(const char (*)[5]))’
prog.cpp:21:19: note: candidate is:
prog.cpp:10:5: note: template<unsigned int N> int foo(typename foo_traits<N>::Function*)
prog.cpp:10:5: note: template argument deduction/substitution failed:
prog.cpp:21:19: note: couldn't deduce template parameter ‘N’
If I use an explicit template argument (i.e., foo<5>(bar)), it compiles fine. If I use a version of the code without the typedefs, it compiles fine:
#include <iostream>
template <unsigned N>
int fixfoo (int (*ptr) (const char (*)[N])) {
return ptr(&"good");
}
int bar (const char (*x)[5]) {
std::cout << *x << "\n";
return 0;
}
int main ()
{
return fixfoo(bar);
}
Is the failing code supposed to compile (i.e., did I make a silly mistake)?
int foo(typename foo_traits<N>::Function *ptr);
The signature makes it a non-deductible context, so you must include the template arguments so that the value N is known and so consequentially the type of the pointer ptr be known as well.
Your second example compiles because the type of the signature through bar can be deduced.