This function template is supposed to return the first element of type X from a tuple using the indexing function, but it won't compile.
template<class X, class F, class... R>
constexpr X getByType(tuple<F, R...> t) {
if (is_same<F,X>::value) {
return get<0>(t); //ERROR POSITION
}
if (sizeof...(R) == 0) {
throw 4;
}
return get_vector<X>(tail(t));
}
int main() {
int i = get<int>(make_tuple(4.2,"assaaa",4));
}
The compiler is saying that it can't cast a double to an int. The first element of this tuple is a double. I guess the reason being the if condition is left to be evaluated at runtime. How can I perform the conditional return of the first element of tuple at compile time?
In case your compiler does not support constexpr-if, you need to factor out some logic into a helper struct.
Example implementation (could certainly be implemented more efficient):
template<class X, class... List>
struct find_first;
template<class X, class... List>
struct find_first<X, X, List...> { static const int value = 0; };
template<class X, class Y, class... List>
struct find_first<X, Y, List...> { static const int value = find_first<X, List...>::value + 1; };
template<class X, class... R>
constexpr X getByType(tuple<R...> t) {
return get<find_first<X,R...>::value>(t);
}
Wandbox-Demo
Related
I have a templated function (Process) where I would like to perform a compile time check to see if the supplied typename (Z) has a templated static member function taking arguments of the two supplied types (X) and (Y).
Is it possible to do this with an if constexpr test and if so, what would it be?
#include <iostream>
struct A { template<typename X, typename Y> static bool compare(const X&, const Y&) { return true; } };
struct B { };
template <typename Z, typename X, typename Y>
inline void Process(X x, Y y)
{
if constexpr (std::is_invocable_v<decltype(Z::compare), const X&, const Y&> )
{
Z::compare(x,y);
}
else {
std::cout << "hi";
}
}
int main()
{
Process<A>(3,2);
Process<B>(3,2);
}
I can't think of a way to do it with if constexpr alone, without a pair of overloads to test with SFINAE. See if something like this works for you:
template <typename Z, typename X, typename Y>
auto test(X x, Y y) ->
std::enable_if_t<sizeof(decltype(Z::compare(x, y))*) != 0, std::true_type>;
template <typename Z>
std::false_type test(...);
template <typename Z, typename X, typename Y>
inline void Process(X x, Y y)
{
if constexpr (decltype(test<Z>(x, y))::value)
{
Z::compare(x,y);
}
else {
std::cout << "hi";
}
}
Demo.
This doesn't test that Z has a templated member function specifically, just that it has a static member function with the right name callable with the right arguments.
I have some templates like the ones below that I can use to define simple expressions
e.g.
Expr<constant,int,int,1,1> = 2
Expr<sub, Expr<constant,int,int,1,1>, Expr<constant,int,int,2,0>, 1, 1> = x - 2.
I want to define a meta-function that takes an Expr and returns another Expr that is a modified version of the one passed as input. The output will be based on the template arguments of the input so I guess I have to define multiple function templates that specialize different inputs. Eventually my goal is to be able to differentiate Expr's.
// the types of expressions (+,-,*, etc.)
enum ExprType { mul, divide, add, sub, constant};
// constant
template <ExprType eType, class Left, class Right, int coeff, int power> struct Expr {
static double eval(double x){
return coeff * std::pow(x, power);
}
};
//sub
template <class Left, class Right, int coeff, int power> struct Expr<sub, Left, Right, coeff, power> {
static double eval(double x){
return coeff * std::pow(Left::eval(x) - Right::eval(x), power);
}
};
// add
template <class Left, class Right, int coeff, int power> struct Expr<add, Left, Right, coeff, power> {
static double eval(double x){
return coeff * std::pow(Left::eval(x) + Right::eval(x), power);
}
};
However, I am having trouble wrapping my head around the function definition. So far I have:
template <template <ExprType eType, class Left, class Right, int coeff, int power> class E> struct ExprDerivative {
static E derivative(E e){
return e;
}
};
Am I going in the right direction? How do I define a meta-function over templates?
You want a type trait, which is a function with types as arguments. A type trait's definition looks nothing like a function on values (they're essentially written in a functional programming style, with "equations"), but they're called as you'd expect (func<args>).
template<typename Differentiand> struct derivative;
// shorthand for calling the function: derivative_t<expr...>
template<typename Differentiand>
using derivative_t = typename derivative<Differentiand>::result;
// every "equation" is a specialization of derivative for a certain set of Exprs that defines the result as a member type
template<typename L, typename R, int coeff, int power>
struct derivative<Expr<constant, L, R, coeff, power>> { using result = Expr<constant, L, R, coeff*power, power - 1> };
// etc
However, I am worried about how you've written the Expr type in the first place. constants are not constants; they're expressions of the form cx^n. Also, they have extraneous left and right operands. It would be better to do this
struct variable {
static constexpr double eval(double x) { return x; }
};
template<int Value>
struct constant {
static constexpr double eval(double x) { return Value; }
};
template<typename Left, typename Right>
struct addition {
static constexpr double eval(double x) { return Left::eval(x) + Right::eval(x); }
};
template<typename Left, typename Right>
struct multiplication {
static constexpr double eval(double x) { return Left::eval(x) * Right::eval(x); }
};
template<typename Base, int Power>
struct exponentiation {
static double eval(double x) { return std::pow(Base::eval(x), Power); }
};
// no need to add these as "primitives"
template<typename Left, typename Right>
using subtraction = addition<Left, multiplication<constant<-1>, Right>>;
template<typename Left, typename Right>
using division = multiplication<Left, exponentiation<Right, -1>>;
The results of differentiation do end up a little less simplified, but you can write another function to clean up after:
template<>
struct derivative<variable> { using result = constant<1>; };
template<int Value>
struct derivative<constant<Value>> { using result = constant<0>; };
template<typename L, typename R>
struct derivative<addition<L, R>> { using result = addition<derivative_t<L>, derivative_t<R>>; };
template<typename L, typename R>
struct derivative<multiplication<L, R>> { using result = addition<multiplication<derivative_t<L>, R>, multiplication<L, derivative_t<R>>>; };
template<typename B, int N>
struct derivative<exponentiation<B, N>> { using result = multiplication<multiplication<constant<N>, exponentiation<B, N - 1>>, derivative_t<B>>; };
E.g.
int main() {
// y = (x^2 + 1)/x
// dy/dx = 1 - x^-2
// dy/dx(x = 2) = 1 - 1/4 = 0.75
std::cout << derivative_t<division<addition<exponentiation<variable, 2>, constant<1>>, variable>>::eval(2) << "\n";
}
Not sure to understand what do you want... but sure you can't pass a template-template argument as a function argument.
Seems to me that your ExprDerivative() functional can be written, as template function that permit to deduce the template-template and the template parameters from the e argument, as follows
template <template <ExprType, typename, typename, int, int> class E,
ExprType eType, typename Left, typename Right,
int coeff, int power>
auto ExprDerivative (E<eType, Left, Right, coeff, power> e)
{ return e; }
Observe that, this way, the argument e is of type E<eType, Left, Right, coeff, power>, not of type E (that isn't a type).
You can use it, by example, as follows
Expr<constant, int, int, 1, 1> e0;
auto e1 = ExprDerivative(e0);
template<typename T, T... Xs> class Nzm
{
private:
template<typename... Ts> static constexpr T Max(Ts... xs);
template<typename Tx> static constexpr T Max(Tx x)
{
return x;
}
template<typename T1, typename T2, typename... Ts> static constexpr T Max(T1 x, T2 y, Ts... xs)
{
return y > x ? Max<T2, Ts...>(y, xs...) : Max<T1, Ts...>(x, xs...);
}
public:
static const T Z = Max(Xs...);
};
int main() {
static_assert(Nzm<int,1,2,3,4,5,6>::Z==5,"XYZ");
return 0;
}
I already know that all the typename are going to be int and I only want to use
Nzm<1,2,3,4,5,6>
instead of
Nzm<int,1,2,3,4,5,6>
this is for compile time execution no code or tips for making it runtime.
is this possible? to set all this typename to int ?
The quick solution is to use a using declaration to get ride of the int.
template<int... x>
using helper = Nzm<int, x...>;
int main() {
static_assert(helper<1, 2, 3, 4, 5, 6>::Z == 6, "XYZ");
return 0;
}
Another (better) way is to modify Nzm and replace all the typename templates with int templates. You're left with a redundancy between the parameters and template arguments, so you can get rid of the parameters.
template<int... Xs> class Nzm
{
private:
template<int x> static constexpr int Max()
{
return x;
}
template<int x, int y, int... rest> static constexpr int Max()
{
return x > y ? Max<x, rest...>() : Max<y, rest...>();
}
public:
static const int Z = Max<Xs...>();
};
int main() {
static_assert(Nzm<1, 2, 3, 4, 5, 6>::Z == 6, "XYZ");
return 0;
}
If you want a template that accepts a parameter pack of ints, have yourself such a template:
template<int ...Is> class Nzm {
// Your implementation follows
};
Templates can accept parameters which aren't types (among them parameters which are integers), and consequently they can accept analogous parameter packs.
I'm writing a compiler that compiles to C++ and am having type issues with my C++ code. The language is meant to be lazy, so we have a lazy value wrapper, Chunk. Here is a part of it, along with the problematic code:
#include <functional>
#include <memory>
template<class T>
class Chunk
{
public:
Chunk();
Chunk(std::function<T()> f);
T operator()();
std::function<T()> f_;
private:
std::shared_ptr<T> cache_;
};
template<class T>
T Chunk<T>::operator()()
{
if(cache_ == nullptr)
cache_ = std::make_shared<T>(f_());
return *cache_;
}
template<class T, class F>
T operator*(Chunk<T> t1, Chunk<F> t2)
{
return t1() * t2();
}
template<class T, class... Args>
T apply(Chunk<std::function<T(Args...)>> c, Args... as)
{
return c()(as...);
}
template<class F>
auto toChunk(F f) -> Chunk<decltype(f())>
{
return Chunk<decltype(f())>(f);
}
template<class T, class F>
struct ops
{
static const auto multiply =
toChunk([]() { return ops::multiply_; });
static const auto multiply_(Chunk<T> x, Chunk<F> y) -> decltype(x * y)
{
return x * y;
}
};
int main()
{
Chunk<double> t = toChunk([]() { return 1.0; });
Chunk<float> f = toChunk([]() { return 2.0f; });
apply(ops::multiply, t, f);
return 0;
}
I can't figure out a definition of multiply to make this work without getting a used without template parameters error. (There may be a second issue here because multiply_ isn't a std::function, but the compiler breaks on the lack of template parameters first.)
I could write a lot of overloads for every pair of types, but this is just really ugly. I tried making multiply a template variable without a template class, and even though I'm using C++14, got cannot resolve address of overloaded function at multiply_ with this alternative definition:
template<class T, class F>
auto multiply_(Chunk<T> x, Chunk<F> y) -> decltype(x * y)
{
return x * y;
}
template<class T, class F>
Chunk<decltype(multiply_)> multiply = toChunk([]() { return multiply_; });
Of course I then changed ops::multiply to simply multiply. Any suggestions to overcome this?
ops is a name of a class template. To refer to members of a class template outside of its definition you need to specify the template arguments.
If you fix this error though, there are going to be more.
I ended up using an entirely different solution. I overloaded apply by adding this second definition:
template<class F, class... Args>
auto apply(F f, Args... as) -> decltype(f(as...))
{
return f(as...);
}
And rewrote multiply as simply:
auto multiply = [](auto x, auto y) { return x * y; };
So our library functions will not be in the lazy wrappers, while user-defined functions (which can't be templates in our language) will.
I've a code smth like this:
template<int N, typename T>
class XYZ {
public:
enum { value = N };
//...
}
Is there a way to restrict N in some way? Specifically I want to allow compilation only if N is divided by some number, let's say 6.
So it turned out to be not just a type restriction.
Preferred way is to do this without Boost.
One C++03 approach:
template<int X, int Y>
struct is_evenly_divisible
{
static bool const value = !(X % Y);
};
template<int N, typename T, bool EnableB = is_evenly_divisible<N, 6>::value>
struct XYZ
{
enum { value = N };
};
template<int N, typename T>
struct XYZ<N, T, false>; // undefined, causes linker error
For C++11, you can avoid some boilerplate and give a nicer error message:
template<int N, typename T>
struct XYZ
{
static_assert(!(N % 6), "N must be evenly divisible by 6");
enum { value = N };
};
I leave this here for the future, since I couldn't find a good example online at the time of posting.
The C++20 way with concepts:
template<int X, int Y>
concept is_evenly_divisible = X % Y == 0;
template <int N, int M> requires is_evenly_divisible<N, M>
struct XYZ
{
enum class something { value = N };
};
XYZ<12, 6> thing; // OK
//XYZ<11, 6> thing; // Error
Or even shorter:
template <int N, int M> requires (N % M == 0)
struct XYZ
{
enum class something { value = N };
};