Dispatch template <auto> - c++

I try to dispatch between two functions using if constexpr. The dispatcher function should accept for example std::size_t and an arbitrary class type.
It works if I just call it with a scalar type, but if I try to pass a class type it triggers a compile error which is not really helpful to me (please see below).
Please have a look at my current approach:
template <auto Other>
constexpr auto mul() const {
if constexpr (std::is_scalar_v<decltype(Other)>)
return mul_with_scalar<Other>();
else
return mul_with_matrix<Other>();
}
template <size_t Scalar>
constexpr auto mul_with_scalar() const {
return apply([](size_t v, auto) { return v * Scalar; },
std::make_index_sequence<Size>{});
}
template <class Other>
constexpr auto mul_with_matrix() const {
return size_t{0}; // implement me
}
note: candidate: template<auto Other> constexpr auto matrix<Rows, Cols, Vals>::mul() const [with auto Other = Other; long unsigned int Rows = 3; long unsigned int Cols = 3; long unsigned int ...Vals = {}]
constexpr auto mul() const {
^~~
./constexpresian/matrix.hpp:81:18: note: template argument deduction/substitution failed:

I wan't that the function mul can handle non-type and type parameters.
That is not possible in C++. A template parameter can be a type or a value (or a template), but it cannot be both. template<auto Name> makes Name a value template parameter, the type of whose value will be deduced at the time the value is passed.
But since it is a compile-time value, you can wrap its value in a type. For integer types, std::integer_constant will work. For future C++ revisions that allow other kinds of value parameters, you'll have to use a more generic wrapper.

There is one question I have, you can refer to my comment below your post that pertains to the term Size.
I tried your code above as is even with Size the way it is to see the compiler errors and this is coming from Visual Studio 2017 v4.6.0105 c++17 on Win 7 x64 Home Premium under x86 Debug on an Intel Quad Core Extreme.
1>------ Build started: Project: StackOverflow, Configuration: Debug Win32 ------
1>Learner.cpp
1>c:\users\skilz80\documents\visual studio 2017\projects\stackoverflow\stackoverflow\learner.h(75): error C3533: a parameter cannot have a type that contains 'auto'
1>c:\users\skilz80\documents\visual studio 2017\projects\stackoverflow\stackoverflow\learner.h(75): error C2270: 'mul': modifiers not allowed on nonmember functions
1>c:\users\skilz80\documents\visual studio 2017\projects\stackoverflow\stackoverflow\learner.h(83): error C2270: 'mul_with_scalar': modifiers not allowed on nonmember functions
1>c:\users\skilz80\documents\visual studio 2017\projects\stackoverflow\stackoverflow\learner.h(89): error C2270: 'mul_with_matrix': modifiers not allowed on nonmember functions
1>Done building project "StackOverflow.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Maybe this interpretation of these compiler errors might help you.
Here are some links that might help concerning auto and template parameters:
StackOverflow : Advantages of auto in template parameters in C++17
open-std.org : Declaring non-type template arguments with auto
www.bfilipek.com : C++17 in details: Templates

Related

Why does the compiler issue a template recursion error?

I'm currently trying to deduce a std::tuple type from several std::vectors that are passed as parameters. My code works fine using gcc, but the compilation fails with Visual Studio Professional 2019 with the message "fatal error C1202: recursive type or function dependency context too complex".
It has been mentioned for my previous post (C++ "fatal error C1202: recursive type or function dependency context too complex" in visual studio, but gcc compiles) that the problem is caused by template recursion as explained in C++ template compilation error - recursive type or function dependency. However, I don't see where the recursion occurs.
So my questions are:
Why is there an (infinite) recursion?
How can it be resolved?
Here is the code (I'm bound to C++11):
#include <tuple>
#include <vector>
template <typename TT,typename Add>
auto addTupBase(TT t,std::vector<Add> a) ->decltype (std::tuple_cat(t,std::make_tuple(a[0])))
{
return std::tuple_cat(t,std::make_tuple(a[0])) ;
}
template <typename TT,typename Add,typename... Args>
auto addTupBase(TT t,std::vector<Add> a,Args... args)-> decltype(addTupBase(addTupBase(t,a),args...))
{
return addTupBase(addTupBase(t,a),args...);
}
template <typename T,typename... Args>
auto addTup(std::vector<T> in,Args... args) ->decltype(addTupBase(std::make_tuple(in[0]),args...))
{
return addTupBase(std::make_tuple(in[0]),args...);
}
int main()
{
using TupleType = decltype(addTup(std::vector<char>{2},std::vector<int>{5},std::vector<double>{32423}));
TupleType t;
std::get<2>(t) = 342.2;
return 0;
}
MSVC has some conformance issues when running in /permissive mode and "The Microsoft C++ compiler doesn't currently support binding nondependent names when initially parsing a template. This doesn't conform to section 14.6.3 of the C++ 11 ISO specification. This can cause overloads declared after the template (but before the template is instantiated) to be seen.".
If you instead use /permissive- "The compiler [...] implements more of the requirements for two-phase name look-up" and will compile your program as-is.
Also note that you aren't actually using C++11. MSVC 19.24 supports C++14 and up.

Couldn't deduce template parameter for Eigen::Matrix

When I try to compile the following function (forward) using MSVC 19.latest I get the following error message.
'Eigen::Matrix<float,ann_output_len<LayerNodeConfig...>::value,1,0,_Rows,1> forward(const
ArtificialNeuralNetwork<InputSize,LayerNodeConfig...> &,const Eigen::Matrix<float,Rows,1,0,_Rows,1> &)':
could not deduce template argument for 'const Eigen::Matrix<float,Rows,1,0,_Rows,1> &' from
'Eigen::Matrix<float,2,1,0,2,1>'
forward interface
template<int InputSize, int ... LayerNodeConfig>
auto forward(const ArtificialNeuralNetwork<InputSize, LayerNodeConfig...>& ann,
const RL::Arrayf<InputSize>& input)
-> typename ANN::output_t<LayerNodeConfig...>
In main function
RL::Arrayf<2> X;
auto Y = forward(sampling_policy, X);
Now what I don't understand is why can't the compiler substitute Rows and _Rows with 2.
Any insight is appreciated.
You can try the full code in godbolt.org using this link, https://godbolt.org/z/7Mj5ee and try to compile it yourself if you like.
Note: I tried to compile the same code with latest GCC compiler and it compiled.
Update - Mar 06, 2021:
I made a workaround by changing the interface of function forward to accept Eigen::DenseBase<Derived> instead of RL::Arrayf<InputSize>.
Anyone who is interested can read more about it here, https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

Template Alias, Variable Template, and auto type deduction failing to deduce template argument

While working on my class declaration I'm having some confusion on how to use alias templates and template variables within in a non class template while trying to use auto type deduction.
Signal.h
#ifndef SIGNAL_H
#define SIGNAL_H
#include <cstdint>
template<typename T>
using TimeSignal = T;
using DiscreteTime = TimeSignal<std::uint8_t>;
using ContinuousTime = TimeSignal<double>;
class Signal {
private:
template<typename T>
static TimeSignal<T> time_;
double voltage_;
double current_;
public:
template<typename T>
explicit Signal( TimeSignal<T> time, double voltage = 0, double current = 0 ) :
voltage_{voltage}, current_{current}
{ time_ = time; }
double sampleVoltage() { return voltage_; }
double sampleCurrent() { return current_; }
template<typename T>
static auto atTime() { return time_; }
};
#endif // SIGNAL_H
And I would be using it like this:
#include <iostream>
#include "Signal.h"
int main() {
DiscreteTime t1{ 5 };
ContinuousTime t2{ 7.5 };
Signal s1{ t1, 3.5, 0.05 );
Signal s2{ t2, 4.3, 0.09 );
auto time1 = s1.atTime();
auto time2 = s2.atTime();
return 0;
}
I don't want to template this class, so I was thinking about having an internal variable template. Outside of the class I was trying to use a template alias to have the different "TimeSignals" be descriptive as a "DiscreteTime" is typically and integral type and a ContinousTime is a floating point or over the set of Real numbers. I was however templating the constructor of this class that takes in the TimeSignal type and wanted the class to deduce the or to auto resolve it's internal variable template to that type depending which of the two types were passed in. Finally I was trying to use auto type deduction to return that type.
I don't know if its the syntax or the usage but this has me stumped. I'm not sure how to get this to a working compile state.
This is the current compiler errors that Visual Studio 2017 is giving me.
1>------ Build started: Project: Circuit Maker Simulator, Configuration: Debug x64 ------
1>main.cpp
1>c:\...\main.cpp(15): error C2672: 'Signal::atTime': no matching overloaded function found
1>c:\...\main.cpp(15): error C2783: 'auto Signal::atTime(void)': could not deduce template argument for 'T'
1>c:\...\Signal.h(64): note: see declaration of 'Signal::atTime'
1>c:\...\main.cpp(24): error C2672: 'Signal::atTime': no matching overloaded function found
1>c:\...\main.cpp(24): error C2783: 'auto Signal::atTime(void)': could not deduce template argument for 'T'
1>c:\...\Signal.h(64): note: see declaration of 'Signal::atTime'
1>Done building project "Circuit Maker Simulator.vcxproj" -- FAILED.
The compiler error's obvious to what they are saying, but it's like they are screaming or yelling at me without any help, assistance or suggestions on how to fix or resolve this...
Edit
User rafix07 helped me quite a bit with his answer and it was helpful. I was missing a couple of things, two of them I may have eventually caught onto if I kept staring at it long enough and that was the use of the variable templates within the class needing it's template argument or parameter. The other was using the scope resolution operator in the main function to call the static function. I could of found them given some time.
The one issue that had me stumbling in circles was the fact that I had to explicitly instantiate the function template of the type I want when calling it. This is the one that would of had me pulling out my hair for ours...
After adjusting the code according to the link in his answer I'm now able to compile, however I am now getting linker errors for unresolved external symbols and it has to do with the template variables. Which shouldn't be a problem, just need to define it within a cpp file to resolve static variables.
First of all, atTime is static method so only way to call it is to use scope resolution operator ::. atTime takes no arguments, so T cannot be deduced, and you need to put type in template arguments list explicitly:
auto time1 = Signal::atTime<DiscreteTime>();
auto time2 = Signal::atTime<ContinuousTime>();
In ctor of Signal and atTime function you have to specify T for which variable template is accessed:
template<typename T>
explicit Signal( TimeSignal<T> time, double voltage = 0, double current = 0 ) :
voltage_{voltage}, current_{current}
{ time_<T> = time; }
Full working code is here.

error: no member named 'rank_' in 'EndIndex'

I am trying to use the automatic differentiation library Adept and I made it work with gcc 4.9.0 and icc 16.0.2 but failed with VS 2017 and Clang 4.0.1
I have reduced the problem to the following snippet and, while I am addressing the issue with the library creators, for the sake of the knowledge I would like to know why this piece of code works in the two mentioned compilers and fails to build in the other two.
template <typename A>
struct Expression
{
static const int rank = A::rank_;
};
struct EndIndex : public Expression<EndIndex>
{
static const int rank_ = 0;
};
int main(int argc, char ** argv)
{
return 0;
}
Output for VS 2017 is:
1>------ Build started: Project: Test, Configuration: Debug Win32 ------
1>Source.cpp
1>d:\Test\source.cpp(4): error C2039: 'rank_': is not a member of 'EndIndex'
1>d:\Test\source.cpp(7): note: see declaration of 'EndIndex'
1>d:\Test\source.cpp(8): note: see reference to class template instantiation 'Expression<EndIndex>' being compiled
1>d:\Test\source.cpp(4): error C2065: 'rank_': undeclared identifier
1>d:\Test\source.cpp(4): error C2131: expression did not evaluate to a constant
1>d:\Test\source.cpp(4): note: failure was caused by non-constant arguments or reference to a non-constant symbol
1>d:\Test\source.cpp(4): note: see usage of 'rank_'
1>Done building project "Test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
And output for Clang 4.0.1:
source.cpp:4:37: error: no member named 'rank_' in 'EndIndex'
static const int rank = A::rank_;
~~~^
source.cpp:7:38: note: in instantiation of template class 'Expression<EndIndex>' requested here
struct EndIndex : public Expression<EndIndex>
It probably happens because rank_ is not defined at that stage.
The following fixes it for Apple LLVM version 9.0.0 (clang-900.0.38):
template <typename A>
struct Expression
{
static const int rank;
};
struct EndIndex : public Expression<EndIndex>
{
static const int rank_ = 0;
};
template <typename A>
const int Expression<A>::rank = A::rank_;
Visual C++ and clang are simply unable to find rank_ member of EndIndex because it's being accessed before declared. Such fancy code often leads to problems in some environments.

Variadic template to proxy QtConcurrent::run functions

I was hoping to create a variadic template function which sits in front of the QtConcurrent::run functions that does some stuff and then passes the parameters on.
QtConcurrent::run is massively overloaded - check out qtconcurrentrun.h
Is it possible to create a variadic template function that I can call which will pass through to QtConcurrent::run ? This is what I have thus far:
template <typename returnT, typename... Args>
static auto Run(Args&&... args) -> QFuture<returnT>
{
// Do Stuff
// Now call through to start the task
QFuture<returnT> future = QtConcurrent::run(std::forward<Args>(args)...);
QFutureWatcher<void>* futureWatcher = new QFutureWatcher<void>(); //A QFutureWatcher<void> is special, see QFutureWatcher QT docs.
futureWatcher->setFuture(future);
QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() {
// Do stuff
futureWatcher->deleteLater();
});
return future;
}
I'm struggling to work out how to deduce the return type, so I've got the returnT as a separate template param. This doesn't compile (VS2012 Nov CTP) when called with:
Tasking::TaskManager::Run<void>([&]() { while (stopTask == false); });
With the top couple error messages being:
1> error C2065: '<lambda_86e0f4508387a4d4f1dd8316ce3048ac>' : undeclared identifier
1> Implementation\TaskingTests\TaskManagerTests.cpp(31) : see reference to function template instantiation 'QFuture<void> Tasking::TaskManager::Run<void,TaskManagerTests::WaitsForTaskTest::<lambda_86e0f4508387a4d4f1dd8316ce3048ac>>(TaskManagerTests::WaitsForTaskTest::<lambda_86e0f4508387a4d4f1dd8316ce3048ac> &&)' being compiled
1>C:\tkbt\Launch2.0.0\ICDE\IceLibrary\Implementation\Tasking/TaskManager.hpp(108): error C2974: 'std::forward' : invalid template argument for '_Ty', type expected
1> C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(1780) : see declaration of 'std::forward'
1> C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(1774) : see declaration of 'std::forward'
1>C:\tkbt\Launch2.0.0\ICDE\IceLibrary\Implementation\Tasking/TaskManager.hpp(108): error C2780: 'QFuture<T> QtConcurrent::run(const Class *,T (__cdecl Class::* )(Param1,Param2,Param3,Param4,Param5) const,const Arg1 &,const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &)' : expects 7 arguments - 0 provided
1> c:\qt\qt5.0.2\5.0.2\msvc2012_64\include\qtconcurrent\qtconcurrentrun.h(333) : see declaration of 'QtConcurrent::run'
Any help much appreciated.
I guess that TaskManager.hpp(108) is the line where you call QtConcurrent::run.
What you are experiencing seems to be this MSVC bug. In short, variadic templates cannot forward lambdas in MSVC. You probably will have to use an oldscool functor in this case or provide nonvariadic overloads to support lambdas, maybe for the first few arguments. If I had to guess I'd think QtConcurrent::run's first argument has to be a function and the other arguments are its parameters, meaning you never get to call Run without arguments. You could rewrite your function template to have one fixed "normal" parameter for the function and the parameter pack for the function arguments.
For the return type deduction you might want to use decltype. Together that would look like this:
template <class F, class... Args>
static auto Run(F&& f, Args&&... args)
-> decltype(QtConcurrent::run(std::forward<F>(f), std::forward<Args>(args)...))
{
auto future = QtConcurrent::run(std::forward<F>(f), std::forward<Args>(args)...);
//I suppose this can not be a smart pointer?
auto futureWatcher = new QFutureWatcher<void>();
futureWatcher->setFuture(future);
QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() {
// Do stuff
futureWatcher->deleteLater();
});
return future;
}
This way, the lambda would be passed to the normal template parameter F, wich should be ok for forwarding, i.e. the bug should not happen this way.
Update: If QtConcurrent::run does not give you the correct return type right away, you could go by using decltype on the function and its arguments:
static auto Run(F&& f, Args&&... args)
-> QtFuture<decltype(f(std::forward<Args>(args)...))>
Maybe you'll need to add some std::remove_reference and std::remove_const to the decltype to get the right future type.