How to use implicit template type deduction
I am trying to write a template to calculate the power of a number during compile time (I am not a template meta-programming expert so any comment is appreciated). Below is the code:
template<typename T, T X, uint64_t P>
struct Pow
{
static constexpr T result = X * Pow<T,X, P - 1>::result;
};
template<typename T, T X>
struct Pow<T, X, 0>
{
static constexpr T result = 1;
};
template<typename T, T X>
struct Pow<T, X, 1>
{
static constexpr T result = X;
};
which I need to call like:
Pow<decltype(4), 4, 2>::result
Question: Is there any way in writing a helper template so that the call skips the decltype
? For example:
Pow<4, 2>::result
I have read the following but so far I couldn't see an answer (it seems quite the opposite) this, this, and this.
c++ templates template-meta-programming decltype
|
show 1 more comment
I am trying to write a template to calculate the power of a number during compile time (I am not a template meta-programming expert so any comment is appreciated). Below is the code:
template<typename T, T X, uint64_t P>
struct Pow
{
static constexpr T result = X * Pow<T,X, P - 1>::result;
};
template<typename T, T X>
struct Pow<T, X, 0>
{
static constexpr T result = 1;
};
template<typename T, T X>
struct Pow<T, X, 1>
{
static constexpr T result = X;
};
which I need to call like:
Pow<decltype(4), 4, 2>::result
Question: Is there any way in writing a helper template so that the call skips the decltype
? For example:
Pow<4, 2>::result
I have read the following but so far I couldn't see an answer (it seems quite the opposite) this, this, and this.
c++ templates template-meta-programming decltype
3
Not a template class, but would aconstexpr
function work equally well, in your case?
– Sam Varshavchik
11 hours ago
Thank you for your answer. i was looking at that as well but i am finding it hard to force it to be used in a constrexpr fashion. this is what code looked like: template <typename T> constexpr T Pow(T num, unsigned int pow) { return pow == 0 ? 1 : num * Pow(num, pow - 1); }
– eucristian
11 hours ago
2
All that should be needed is your existing template class, as shown in the question, and aconstexpr
function that returnsPow<T, x, y>::result
; which will be logically equivalent, at compile time, to what you have here.
– Sam Varshavchik
11 hours ago
I am a bit more afraid of people using it in something std::cout << Pow<2,4> which to my understanding would circumvent the constrexpr-ness of the template. (i might be wrong and it might be the same but my understanding is that this is more contextually dependent as where to keep the constexpresness of it)
– eucristian
11 hours ago
2
Maybe the exponent should be an unsigned type, not a signed type. It will break onPow<double, 2.0, -1>
.
– aschepler
9 hours ago
|
show 1 more comment
I am trying to write a template to calculate the power of a number during compile time (I am not a template meta-programming expert so any comment is appreciated). Below is the code:
template<typename T, T X, uint64_t P>
struct Pow
{
static constexpr T result = X * Pow<T,X, P - 1>::result;
};
template<typename T, T X>
struct Pow<T, X, 0>
{
static constexpr T result = 1;
};
template<typename T, T X>
struct Pow<T, X, 1>
{
static constexpr T result = X;
};
which I need to call like:
Pow<decltype(4), 4, 2>::result
Question: Is there any way in writing a helper template so that the call skips the decltype
? For example:
Pow<4, 2>::result
I have read the following but so far I couldn't see an answer (it seems quite the opposite) this, this, and this.
c++ templates template-meta-programming decltype
I am trying to write a template to calculate the power of a number during compile time (I am not a template meta-programming expert so any comment is appreciated). Below is the code:
template<typename T, T X, uint64_t P>
struct Pow
{
static constexpr T result = X * Pow<T,X, P - 1>::result;
};
template<typename T, T X>
struct Pow<T, X, 0>
{
static constexpr T result = 1;
};
template<typename T, T X>
struct Pow<T, X, 1>
{
static constexpr T result = X;
};
which I need to call like:
Pow<decltype(4), 4, 2>::result
Question: Is there any way in writing a helper template so that the call skips the decltype
? For example:
Pow<4, 2>::result
I have read the following but so far I couldn't see an answer (it seems quite the opposite) this, this, and this.
c++ templates template-meta-programming decltype
c++ templates template-meta-programming decltype
edited 5 hours ago
Null
1,47861926
1,47861926
asked 11 hours ago
eucristianeucristian
7116
7116
3
Not a template class, but would aconstexpr
function work equally well, in your case?
– Sam Varshavchik
11 hours ago
Thank you for your answer. i was looking at that as well but i am finding it hard to force it to be used in a constrexpr fashion. this is what code looked like: template <typename T> constexpr T Pow(T num, unsigned int pow) { return pow == 0 ? 1 : num * Pow(num, pow - 1); }
– eucristian
11 hours ago
2
All that should be needed is your existing template class, as shown in the question, and aconstexpr
function that returnsPow<T, x, y>::result
; which will be logically equivalent, at compile time, to what you have here.
– Sam Varshavchik
11 hours ago
I am a bit more afraid of people using it in something std::cout << Pow<2,4> which to my understanding would circumvent the constrexpr-ness of the template. (i might be wrong and it might be the same but my understanding is that this is more contextually dependent as where to keep the constexpresness of it)
– eucristian
11 hours ago
2
Maybe the exponent should be an unsigned type, not a signed type. It will break onPow<double, 2.0, -1>
.
– aschepler
9 hours ago
|
show 1 more comment
3
Not a template class, but would aconstexpr
function work equally well, in your case?
– Sam Varshavchik
11 hours ago
Thank you for your answer. i was looking at that as well but i am finding it hard to force it to be used in a constrexpr fashion. this is what code looked like: template <typename T> constexpr T Pow(T num, unsigned int pow) { return pow == 0 ? 1 : num * Pow(num, pow - 1); }
– eucristian
11 hours ago
2
All that should be needed is your existing template class, as shown in the question, and aconstexpr
function that returnsPow<T, x, y>::result
; which will be logically equivalent, at compile time, to what you have here.
– Sam Varshavchik
11 hours ago
I am a bit more afraid of people using it in something std::cout << Pow<2,4> which to my understanding would circumvent the constrexpr-ness of the template. (i might be wrong and it might be the same but my understanding is that this is more contextually dependent as where to keep the constexpresness of it)
– eucristian
11 hours ago
2
Maybe the exponent should be an unsigned type, not a signed type. It will break onPow<double, 2.0, -1>
.
– aschepler
9 hours ago
3
3
Not a template class, but would a
constexpr
function work equally well, in your case?– Sam Varshavchik
11 hours ago
Not a template class, but would a
constexpr
function work equally well, in your case?– Sam Varshavchik
11 hours ago
Thank you for your answer. i was looking at that as well but i am finding it hard to force it to be used in a constrexpr fashion. this is what code looked like: template <typename T> constexpr T Pow(T num, unsigned int pow) { return pow == 0 ? 1 : num * Pow(num, pow - 1); }
– eucristian
11 hours ago
Thank you for your answer. i was looking at that as well but i am finding it hard to force it to be used in a constrexpr fashion. this is what code looked like: template <typename T> constexpr T Pow(T num, unsigned int pow) { return pow == 0 ? 1 : num * Pow(num, pow - 1); }
– eucristian
11 hours ago
2
2
All that should be needed is your existing template class, as shown in the question, and a
constexpr
function that returns Pow<T, x, y>::result
; which will be logically equivalent, at compile time, to what you have here.– Sam Varshavchik
11 hours ago
All that should be needed is your existing template class, as shown in the question, and a
constexpr
function that returns Pow<T, x, y>::result
; which will be logically equivalent, at compile time, to what you have here.– Sam Varshavchik
11 hours ago
I am a bit more afraid of people using it in something std::cout << Pow<2,4> which to my understanding would circumvent the constrexpr-ness of the template. (i might be wrong and it might be the same but my understanding is that this is more contextually dependent as where to keep the constexpresness of it)
– eucristian
11 hours ago
I am a bit more afraid of people using it in something std::cout << Pow<2,4> which to my understanding would circumvent the constrexpr-ness of the template. (i might be wrong and it might be the same but my understanding is that this is more contextually dependent as where to keep the constexpresness of it)
– eucristian
11 hours ago
2
2
Maybe the exponent should be an unsigned type, not a signed type. It will break on
Pow<double, 2.0, -1>
.– aschepler
9 hours ago
Maybe the exponent should be an unsigned type, not a signed type. It will break on
Pow<double, 2.0, -1>
.– aschepler
9 hours ago
|
show 1 more comment
2 Answers
2
active
oldest
votes
Starting from C++17, you can use an auto
type for the X
template value
template <auto X, int64_t P>
struct Pow
{
static constexpr decltype(X) result = X * Pow<X, P - 1>::result;
};
template <auto X>
struct Pow<X, 0>
{
static constexpr decltype(X) result = 1;
};
And you can also see that, given the 0
partial specialization, the 1
partial specialization is superfluous (also C++11/C++14).
Before C++17... the best I can imagine, to avoid to explicit the T
type, pass through a macro definition (that usually is heavily discouraged but, in this case, I suppose can be reasonable).
Something as
#define PowMacro(X, P) Pow<decltype(X), X, P>
2
"The1
partial specialization is superfluous"... unlessT
is a class type representing some sort of mathematical ring without unit or semigroup, or otherwise for some reason does not support initialization from the expression1
.
– aschepler
9 hours ago
1
@aschepler - good point... from the theoretical point of view... but, practically speaking, whichT
type, the values of witch can be template parameters, can't accept initialization from1
but support multiplication?
– max66
6 hours ago
add a comment |
Sure you can skip the decltype, and you need no structures when using C++ 11 contexpr. For example:
#include <iostream>
#include <type_traits>
template<typename T, class = typename std::enable_if< std::is_arithmetic<T>::value >::type >
constexpr T pow(T n, T power) noexcept {
return power == 1 ? n : n * pow(n,power - 1);
}
int main(int argc, const char* argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
return 0;
}
P.S.
Faster way for racing number in a power. Real code should use something like that since compilation time also does matters.
#include <iostream>
#include <type_traits>
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
template<typename T>
constexpr T pow(const T base,const T power, typename std::enable_if< std::is_integral<T>::value >::type* = 0) {
return 1 == power
? base
: 0 == power
? 1
: (1 == (power & 1) )
? base * pow(base, power - 1)
: pow(base, (power >> 1) ) * pow( base, (power >> 1) );
}
#ifdef __GNUG__
// GCC able to use most of <cmath> at compile time, check <cmath> header
inline constexpr float pow(float base, float power) noexcept {
return __builtin_powf(base, power);
}
inline constexpr double pow(double base, double power) noexcept {
return __builtin_pow(base, power);
}
inline constexpr long double pow(long double base,long double power) noexcept {
return __builtin_powl(base, power);
}
#else
// slow
template<typename T>
constexpr T pow(T base, T power, typename std::enable_if< std::is_floating_point<T>::value >::type* = 0) noexcept {
return power == 1.0 ? base : base * pow(base,power - static_cast<T>(1.0) );
}
#endif // __GNUG__
int main(int argc, const char** argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 1024 == pow(2L,10L) ,"wrong pow");
static_assert( (1 << 20) == pow(2LL,20LL) ,"wrong pow");
std::cout << "integer 2^1=" << pow(2, 1) << std::endl;
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "long 2^10=" << pow(2L, 10L) << std::endl;
std::cout << "long long 2^20=" << pow(2LL, 20LL) << std::endl;
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
static_assert( 1024.0L == pow(2.0L,10.0L) ,"wrong pow");
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
std::cout << "long double 2^10=" << pow(2.0L, 10.0L) << std::endl;
return 0;
}
1
Thank you for your answer. I have also read this but i have a question. Without the static_assert bit there would be no way to guarantee the compile time calculated. Is this correct?
– eucristian
10 hours ago
constexpr so in case of something likelong double foo(long double bar, float buz) { return log(bar,MATH_PI) * pow(bar, sqrt(buz) ) ; }
off cause it is not going to be a compile time. But in this case i think - it should not be a compile time. Unlike something likestatic constexpr long double FOO = pow(128.0,500.0D)
;
– Victor Gubin
10 hours ago
1
BTW, the best way to check - compiler assembly output.
– Victor Gubin
10 hours ago
2
If you want a compile time error when the arguments topow
are not constexpr, you can juststatic_assert(n == n, "not constexpr call"); static_assert(power == power, "not constexpr call");
– Caleth
9 hours ago
when you invoke the function in a compile-time context (either by storing the result asconstexpr
or by usingstatic_assert
) your compiler will automatically fail to compile with some kind of "no constexpr"-message. I don't see any value in checking the parameters for constants...
– fdan
9 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54748610%2fhow-to-use-implicit-template-type-deduction%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Starting from C++17, you can use an auto
type for the X
template value
template <auto X, int64_t P>
struct Pow
{
static constexpr decltype(X) result = X * Pow<X, P - 1>::result;
};
template <auto X>
struct Pow<X, 0>
{
static constexpr decltype(X) result = 1;
};
And you can also see that, given the 0
partial specialization, the 1
partial specialization is superfluous (also C++11/C++14).
Before C++17... the best I can imagine, to avoid to explicit the T
type, pass through a macro definition (that usually is heavily discouraged but, in this case, I suppose can be reasonable).
Something as
#define PowMacro(X, P) Pow<decltype(X), X, P>
2
"The1
partial specialization is superfluous"... unlessT
is a class type representing some sort of mathematical ring without unit or semigroup, or otherwise for some reason does not support initialization from the expression1
.
– aschepler
9 hours ago
1
@aschepler - good point... from the theoretical point of view... but, practically speaking, whichT
type, the values of witch can be template parameters, can't accept initialization from1
but support multiplication?
– max66
6 hours ago
add a comment |
Starting from C++17, you can use an auto
type for the X
template value
template <auto X, int64_t P>
struct Pow
{
static constexpr decltype(X) result = X * Pow<X, P - 1>::result;
};
template <auto X>
struct Pow<X, 0>
{
static constexpr decltype(X) result = 1;
};
And you can also see that, given the 0
partial specialization, the 1
partial specialization is superfluous (also C++11/C++14).
Before C++17... the best I can imagine, to avoid to explicit the T
type, pass through a macro definition (that usually is heavily discouraged but, in this case, I suppose can be reasonable).
Something as
#define PowMacro(X, P) Pow<decltype(X), X, P>
2
"The1
partial specialization is superfluous"... unlessT
is a class type representing some sort of mathematical ring without unit or semigroup, or otherwise for some reason does not support initialization from the expression1
.
– aschepler
9 hours ago
1
@aschepler - good point... from the theoretical point of view... but, practically speaking, whichT
type, the values of witch can be template parameters, can't accept initialization from1
but support multiplication?
– max66
6 hours ago
add a comment |
Starting from C++17, you can use an auto
type for the X
template value
template <auto X, int64_t P>
struct Pow
{
static constexpr decltype(X) result = X * Pow<X, P - 1>::result;
};
template <auto X>
struct Pow<X, 0>
{
static constexpr decltype(X) result = 1;
};
And you can also see that, given the 0
partial specialization, the 1
partial specialization is superfluous (also C++11/C++14).
Before C++17... the best I can imagine, to avoid to explicit the T
type, pass through a macro definition (that usually is heavily discouraged but, in this case, I suppose can be reasonable).
Something as
#define PowMacro(X, P) Pow<decltype(X), X, P>
Starting from C++17, you can use an auto
type for the X
template value
template <auto X, int64_t P>
struct Pow
{
static constexpr decltype(X) result = X * Pow<X, P - 1>::result;
};
template <auto X>
struct Pow<X, 0>
{
static constexpr decltype(X) result = 1;
};
And you can also see that, given the 0
partial specialization, the 1
partial specialization is superfluous (also C++11/C++14).
Before C++17... the best I can imagine, to avoid to explicit the T
type, pass through a macro definition (that usually is heavily discouraged but, in this case, I suppose can be reasonable).
Something as
#define PowMacro(X, P) Pow<decltype(X), X, P>
edited 9 hours ago
answered 11 hours ago
max66max66
36.8k74166
36.8k74166
2
"The1
partial specialization is superfluous"... unlessT
is a class type representing some sort of mathematical ring without unit or semigroup, or otherwise for some reason does not support initialization from the expression1
.
– aschepler
9 hours ago
1
@aschepler - good point... from the theoretical point of view... but, practically speaking, whichT
type, the values of witch can be template parameters, can't accept initialization from1
but support multiplication?
– max66
6 hours ago
add a comment |
2
"The1
partial specialization is superfluous"... unlessT
is a class type representing some sort of mathematical ring without unit or semigroup, or otherwise for some reason does not support initialization from the expression1
.
– aschepler
9 hours ago
1
@aschepler - good point... from the theoretical point of view... but, practically speaking, whichT
type, the values of witch can be template parameters, can't accept initialization from1
but support multiplication?
– max66
6 hours ago
2
2
"The
1
partial specialization is superfluous"... unless T
is a class type representing some sort of mathematical ring without unit or semigroup, or otherwise for some reason does not support initialization from the expression 1
.– aschepler
9 hours ago
"The
1
partial specialization is superfluous"... unless T
is a class type representing some sort of mathematical ring without unit or semigroup, or otherwise for some reason does not support initialization from the expression 1
.– aschepler
9 hours ago
1
1
@aschepler - good point... from the theoretical point of view... but, practically speaking, which
T
type, the values of witch can be template parameters, can't accept initialization from 1
but support multiplication?– max66
6 hours ago
@aschepler - good point... from the theoretical point of view... but, practically speaking, which
T
type, the values of witch can be template parameters, can't accept initialization from 1
but support multiplication?– max66
6 hours ago
add a comment |
Sure you can skip the decltype, and you need no structures when using C++ 11 contexpr. For example:
#include <iostream>
#include <type_traits>
template<typename T, class = typename std::enable_if< std::is_arithmetic<T>::value >::type >
constexpr T pow(T n, T power) noexcept {
return power == 1 ? n : n * pow(n,power - 1);
}
int main(int argc, const char* argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
return 0;
}
P.S.
Faster way for racing number in a power. Real code should use something like that since compilation time also does matters.
#include <iostream>
#include <type_traits>
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
template<typename T>
constexpr T pow(const T base,const T power, typename std::enable_if< std::is_integral<T>::value >::type* = 0) {
return 1 == power
? base
: 0 == power
? 1
: (1 == (power & 1) )
? base * pow(base, power - 1)
: pow(base, (power >> 1) ) * pow( base, (power >> 1) );
}
#ifdef __GNUG__
// GCC able to use most of <cmath> at compile time, check <cmath> header
inline constexpr float pow(float base, float power) noexcept {
return __builtin_powf(base, power);
}
inline constexpr double pow(double base, double power) noexcept {
return __builtin_pow(base, power);
}
inline constexpr long double pow(long double base,long double power) noexcept {
return __builtin_powl(base, power);
}
#else
// slow
template<typename T>
constexpr T pow(T base, T power, typename std::enable_if< std::is_floating_point<T>::value >::type* = 0) noexcept {
return power == 1.0 ? base : base * pow(base,power - static_cast<T>(1.0) );
}
#endif // __GNUG__
int main(int argc, const char** argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 1024 == pow(2L,10L) ,"wrong pow");
static_assert( (1 << 20) == pow(2LL,20LL) ,"wrong pow");
std::cout << "integer 2^1=" << pow(2, 1) << std::endl;
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "long 2^10=" << pow(2L, 10L) << std::endl;
std::cout << "long long 2^20=" << pow(2LL, 20LL) << std::endl;
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
static_assert( 1024.0L == pow(2.0L,10.0L) ,"wrong pow");
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
std::cout << "long double 2^10=" << pow(2.0L, 10.0L) << std::endl;
return 0;
}
1
Thank you for your answer. I have also read this but i have a question. Without the static_assert bit there would be no way to guarantee the compile time calculated. Is this correct?
– eucristian
10 hours ago
constexpr so in case of something likelong double foo(long double bar, float buz) { return log(bar,MATH_PI) * pow(bar, sqrt(buz) ) ; }
off cause it is not going to be a compile time. But in this case i think - it should not be a compile time. Unlike something likestatic constexpr long double FOO = pow(128.0,500.0D)
;
– Victor Gubin
10 hours ago
1
BTW, the best way to check - compiler assembly output.
– Victor Gubin
10 hours ago
2
If you want a compile time error when the arguments topow
are not constexpr, you can juststatic_assert(n == n, "not constexpr call"); static_assert(power == power, "not constexpr call");
– Caleth
9 hours ago
when you invoke the function in a compile-time context (either by storing the result asconstexpr
or by usingstatic_assert
) your compiler will automatically fail to compile with some kind of "no constexpr"-message. I don't see any value in checking the parameters for constants...
– fdan
9 hours ago
add a comment |
Sure you can skip the decltype, and you need no structures when using C++ 11 contexpr. For example:
#include <iostream>
#include <type_traits>
template<typename T, class = typename std::enable_if< std::is_arithmetic<T>::value >::type >
constexpr T pow(T n, T power) noexcept {
return power == 1 ? n : n * pow(n,power - 1);
}
int main(int argc, const char* argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
return 0;
}
P.S.
Faster way for racing number in a power. Real code should use something like that since compilation time also does matters.
#include <iostream>
#include <type_traits>
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
template<typename T>
constexpr T pow(const T base,const T power, typename std::enable_if< std::is_integral<T>::value >::type* = 0) {
return 1 == power
? base
: 0 == power
? 1
: (1 == (power & 1) )
? base * pow(base, power - 1)
: pow(base, (power >> 1) ) * pow( base, (power >> 1) );
}
#ifdef __GNUG__
// GCC able to use most of <cmath> at compile time, check <cmath> header
inline constexpr float pow(float base, float power) noexcept {
return __builtin_powf(base, power);
}
inline constexpr double pow(double base, double power) noexcept {
return __builtin_pow(base, power);
}
inline constexpr long double pow(long double base,long double power) noexcept {
return __builtin_powl(base, power);
}
#else
// slow
template<typename T>
constexpr T pow(T base, T power, typename std::enable_if< std::is_floating_point<T>::value >::type* = 0) noexcept {
return power == 1.0 ? base : base * pow(base,power - static_cast<T>(1.0) );
}
#endif // __GNUG__
int main(int argc, const char** argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 1024 == pow(2L,10L) ,"wrong pow");
static_assert( (1 << 20) == pow(2LL,20LL) ,"wrong pow");
std::cout << "integer 2^1=" << pow(2, 1) << std::endl;
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "long 2^10=" << pow(2L, 10L) << std::endl;
std::cout << "long long 2^20=" << pow(2LL, 20LL) << std::endl;
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
static_assert( 1024.0L == pow(2.0L,10.0L) ,"wrong pow");
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
std::cout << "long double 2^10=" << pow(2.0L, 10.0L) << std::endl;
return 0;
}
1
Thank you for your answer. I have also read this but i have a question. Without the static_assert bit there would be no way to guarantee the compile time calculated. Is this correct?
– eucristian
10 hours ago
constexpr so in case of something likelong double foo(long double bar, float buz) { return log(bar,MATH_PI) * pow(bar, sqrt(buz) ) ; }
off cause it is not going to be a compile time. But in this case i think - it should not be a compile time. Unlike something likestatic constexpr long double FOO = pow(128.0,500.0D)
;
– Victor Gubin
10 hours ago
1
BTW, the best way to check - compiler assembly output.
– Victor Gubin
10 hours ago
2
If you want a compile time error when the arguments topow
are not constexpr, you can juststatic_assert(n == n, "not constexpr call"); static_assert(power == power, "not constexpr call");
– Caleth
9 hours ago
when you invoke the function in a compile-time context (either by storing the result asconstexpr
or by usingstatic_assert
) your compiler will automatically fail to compile with some kind of "no constexpr"-message. I don't see any value in checking the parameters for constants...
– fdan
9 hours ago
add a comment |
Sure you can skip the decltype, and you need no structures when using C++ 11 contexpr. For example:
#include <iostream>
#include <type_traits>
template<typename T, class = typename std::enable_if< std::is_arithmetic<T>::value >::type >
constexpr T pow(T n, T power) noexcept {
return power == 1 ? n : n * pow(n,power - 1);
}
int main(int argc, const char* argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
return 0;
}
P.S.
Faster way for racing number in a power. Real code should use something like that since compilation time also does matters.
#include <iostream>
#include <type_traits>
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
template<typename T>
constexpr T pow(const T base,const T power, typename std::enable_if< std::is_integral<T>::value >::type* = 0) {
return 1 == power
? base
: 0 == power
? 1
: (1 == (power & 1) )
? base * pow(base, power - 1)
: pow(base, (power >> 1) ) * pow( base, (power >> 1) );
}
#ifdef __GNUG__
// GCC able to use most of <cmath> at compile time, check <cmath> header
inline constexpr float pow(float base, float power) noexcept {
return __builtin_powf(base, power);
}
inline constexpr double pow(double base, double power) noexcept {
return __builtin_pow(base, power);
}
inline constexpr long double pow(long double base,long double power) noexcept {
return __builtin_powl(base, power);
}
#else
// slow
template<typename T>
constexpr T pow(T base, T power, typename std::enable_if< std::is_floating_point<T>::value >::type* = 0) noexcept {
return power == 1.0 ? base : base * pow(base,power - static_cast<T>(1.0) );
}
#endif // __GNUG__
int main(int argc, const char** argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 1024 == pow(2L,10L) ,"wrong pow");
static_assert( (1 << 20) == pow(2LL,20LL) ,"wrong pow");
std::cout << "integer 2^1=" << pow(2, 1) << std::endl;
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "long 2^10=" << pow(2L, 10L) << std::endl;
std::cout << "long long 2^20=" << pow(2LL, 20LL) << std::endl;
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
static_assert( 1024.0L == pow(2.0L,10.0L) ,"wrong pow");
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
std::cout << "long double 2^10=" << pow(2.0L, 10.0L) << std::endl;
return 0;
}
Sure you can skip the decltype, and you need no structures when using C++ 11 contexpr. For example:
#include <iostream>
#include <type_traits>
template<typename T, class = typename std::enable_if< std::is_arithmetic<T>::value >::type >
constexpr T pow(T n, T power) noexcept {
return power == 1 ? n : n * pow(n,power - 1);
}
int main(int argc, const char* argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
return 0;
}
P.S.
Faster way for racing number in a power. Real code should use something like that since compilation time also does matters.
#include <iostream>
#include <type_traits>
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
template<typename T>
constexpr T pow(const T base,const T power, typename std::enable_if< std::is_integral<T>::value >::type* = 0) {
return 1 == power
? base
: 0 == power
? 1
: (1 == (power & 1) )
? base * pow(base, power - 1)
: pow(base, (power >> 1) ) * pow( base, (power >> 1) );
}
#ifdef __GNUG__
// GCC able to use most of <cmath> at compile time, check <cmath> header
inline constexpr float pow(float base, float power) noexcept {
return __builtin_powf(base, power);
}
inline constexpr double pow(double base, double power) noexcept {
return __builtin_pow(base, power);
}
inline constexpr long double pow(long double base,long double power) noexcept {
return __builtin_powl(base, power);
}
#else
// slow
template<typename T>
constexpr T pow(T base, T power, typename std::enable_if< std::is_floating_point<T>::value >::type* = 0) noexcept {
return power == 1.0 ? base : base * pow(base,power - static_cast<T>(1.0) );
}
#endif // __GNUG__
int main(int argc, const char** argv) {
static_assert( 4 == pow(2,2) ,"wrong pow");
static_assert( 1024 == pow(2L,10L) ,"wrong pow");
static_assert( (1 << 20) == pow(2LL,20LL) ,"wrong pow");
std::cout << "integer 2^1=" << pow(2, 1) << std::endl;
std::cout << "integer 2^2=" << pow(2, 2) << std::endl;
std::cout << "long 2^10=" << pow(2L, 10L) << std::endl;
std::cout << "long long 2^20=" << pow(2LL, 20LL) << std::endl;
static_assert( 8.0F == pow(2.0F,3.0F) ,"wrong pow");
static_assert( 256.0 == pow(2.0,8.0) ,"wrong pow");
static_assert( 1024.0L == pow(2.0L,10.0L) ,"wrong pow");
std::cout << "float 2^3=" << pow(2.0F, 3.0F) << std::endl;
std::cout << "double 2^8=" << pow(2.0, 8.0) << std::endl;
std::cout << "long double 2^10=" << pow(2.0L, 10.0L) << std::endl;
return 0;
}
edited 4 hours ago
answered 11 hours ago
Victor GubinVictor Gubin
1,468212
1,468212
1
Thank you for your answer. I have also read this but i have a question. Without the static_assert bit there would be no way to guarantee the compile time calculated. Is this correct?
– eucristian
10 hours ago
constexpr so in case of something likelong double foo(long double bar, float buz) { return log(bar,MATH_PI) * pow(bar, sqrt(buz) ) ; }
off cause it is not going to be a compile time. But in this case i think - it should not be a compile time. Unlike something likestatic constexpr long double FOO = pow(128.0,500.0D)
;
– Victor Gubin
10 hours ago
1
BTW, the best way to check - compiler assembly output.
– Victor Gubin
10 hours ago
2
If you want a compile time error when the arguments topow
are not constexpr, you can juststatic_assert(n == n, "not constexpr call"); static_assert(power == power, "not constexpr call");
– Caleth
9 hours ago
when you invoke the function in a compile-time context (either by storing the result asconstexpr
or by usingstatic_assert
) your compiler will automatically fail to compile with some kind of "no constexpr"-message. I don't see any value in checking the parameters for constants...
– fdan
9 hours ago
add a comment |
1
Thank you for your answer. I have also read this but i have a question. Without the static_assert bit there would be no way to guarantee the compile time calculated. Is this correct?
– eucristian
10 hours ago
constexpr so in case of something likelong double foo(long double bar, float buz) { return log(bar,MATH_PI) * pow(bar, sqrt(buz) ) ; }
off cause it is not going to be a compile time. But in this case i think - it should not be a compile time. Unlike something likestatic constexpr long double FOO = pow(128.0,500.0D)
;
– Victor Gubin
10 hours ago
1
BTW, the best way to check - compiler assembly output.
– Victor Gubin
10 hours ago
2
If you want a compile time error when the arguments topow
are not constexpr, you can juststatic_assert(n == n, "not constexpr call"); static_assert(power == power, "not constexpr call");
– Caleth
9 hours ago
when you invoke the function in a compile-time context (either by storing the result asconstexpr
or by usingstatic_assert
) your compiler will automatically fail to compile with some kind of "no constexpr"-message. I don't see any value in checking the parameters for constants...
– fdan
9 hours ago
1
1
Thank you for your answer. I have also read this but i have a question. Without the static_assert bit there would be no way to guarantee the compile time calculated. Is this correct?
– eucristian
10 hours ago
Thank you for your answer. I have also read this but i have a question. Without the static_assert bit there would be no way to guarantee the compile time calculated. Is this correct?
– eucristian
10 hours ago
constexpr so in case of something like
long double foo(long double bar, float buz) { return log(bar,MATH_PI) * pow(bar, sqrt(buz) ) ; }
off cause it is not going to be a compile time. But in this case i think - it should not be a compile time. Unlike something like static constexpr long double FOO = pow(128.0,500.0D)
;– Victor Gubin
10 hours ago
constexpr so in case of something like
long double foo(long double bar, float buz) { return log(bar,MATH_PI) * pow(bar, sqrt(buz) ) ; }
off cause it is not going to be a compile time. But in this case i think - it should not be a compile time. Unlike something like static constexpr long double FOO = pow(128.0,500.0D)
;– Victor Gubin
10 hours ago
1
1
BTW, the best way to check - compiler assembly output.
– Victor Gubin
10 hours ago
BTW, the best way to check - compiler assembly output.
– Victor Gubin
10 hours ago
2
2
If you want a compile time error when the arguments to
pow
are not constexpr, you can just static_assert(n == n, "not constexpr call"); static_assert(power == power, "not constexpr call");
– Caleth
9 hours ago
If you want a compile time error when the arguments to
pow
are not constexpr, you can just static_assert(n == n, "not constexpr call"); static_assert(power == power, "not constexpr call");
– Caleth
9 hours ago
when you invoke the function in a compile-time context (either by storing the result as
constexpr
or by using static_assert
) your compiler will automatically fail to compile with some kind of "no constexpr"-message. I don't see any value in checking the parameters for constants...– fdan
9 hours ago
when you invoke the function in a compile-time context (either by storing the result as
constexpr
or by using static_assert
) your compiler will automatically fail to compile with some kind of "no constexpr"-message. I don't see any value in checking the parameters for constants...– fdan
9 hours ago
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54748610%2fhow-to-use-implicit-template-type-deduction%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
Not a template class, but would a
constexpr
function work equally well, in your case?– Sam Varshavchik
11 hours ago
Thank you for your answer. i was looking at that as well but i am finding it hard to force it to be used in a constrexpr fashion. this is what code looked like: template <typename T> constexpr T Pow(T num, unsigned int pow) { return pow == 0 ? 1 : num * Pow(num, pow - 1); }
– eucristian
11 hours ago
2
All that should be needed is your existing template class, as shown in the question, and a
constexpr
function that returnsPow<T, x, y>::result
; which will be logically equivalent, at compile time, to what you have here.– Sam Varshavchik
11 hours ago
I am a bit more afraid of people using it in something std::cout << Pow<2,4> which to my understanding would circumvent the constrexpr-ness of the template. (i might be wrong and it might be the same but my understanding is that this is more contextually dependent as where to keep the constexpresness of it)
– eucristian
11 hours ago
2
Maybe the exponent should be an unsigned type, not a signed type. It will break on
Pow<double, 2.0, -1>
.– aschepler
9 hours ago