How to write this C++17 static constexpr method in C++11?
What is the most concise way to write the below static constexpr size_t Foo<>::sum()
method in C++11? This works fine with C++17 compilers, but I'm looking for a way that works on g++, clang, and Visual Studio 2015 in C++11 mode.
#include <iostream>
#include <type_traits>
template<typename T,size_t N>
class Foo
{
public:
static constexpr size_t sum();
};
template<typename>
struct is_foo : std::false_type { };
template<typename T,size_t N>
struct is_foo<Foo<T,N>> : std::true_type { };
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
if constexpr (is_foo<T>::value)
return N + T::sum();
else
return N;
}
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
Compile and run:
$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
...
$ g++ -std=c++17 sum.cpp
$ ./a.out
sum = 12
I'm able to write an external functor for sum()
that accomplishes this, but I would really like for it to be a static constexpr
member function as above. Is this even possible in C++11?
c++ c++11 templates c++17 template-meta-programming
add a comment |
What is the most concise way to write the below static constexpr size_t Foo<>::sum()
method in C++11? This works fine with C++17 compilers, but I'm looking for a way that works on g++, clang, and Visual Studio 2015 in C++11 mode.
#include <iostream>
#include <type_traits>
template<typename T,size_t N>
class Foo
{
public:
static constexpr size_t sum();
};
template<typename>
struct is_foo : std::false_type { };
template<typename T,size_t N>
struct is_foo<Foo<T,N>> : std::true_type { };
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
if constexpr (is_foo<T>::value)
return N + T::sum();
else
return N;
}
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
Compile and run:
$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
...
$ g++ -std=c++17 sum.cpp
$ ./a.out
sum = 12
I'm able to write an external functor for sum()
that accomplishes this, but I would really like for it to be a static constexpr
member function as above. Is this even possible in C++11?
c++ c++11 templates c++17 template-meta-programming
You're just asking how to replace theif constexpr
then, right?enable_if
?
– Lightness Races in Orbit
Jan 1 at 21:19
I tried SFINAE withconstexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum()
but am getting the errorprototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'
.
– Matt
Jan 2 at 15:59
add a comment |
What is the most concise way to write the below static constexpr size_t Foo<>::sum()
method in C++11? This works fine with C++17 compilers, but I'm looking for a way that works on g++, clang, and Visual Studio 2015 in C++11 mode.
#include <iostream>
#include <type_traits>
template<typename T,size_t N>
class Foo
{
public:
static constexpr size_t sum();
};
template<typename>
struct is_foo : std::false_type { };
template<typename T,size_t N>
struct is_foo<Foo<T,N>> : std::true_type { };
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
if constexpr (is_foo<T>::value)
return N + T::sum();
else
return N;
}
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
Compile and run:
$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
...
$ g++ -std=c++17 sum.cpp
$ ./a.out
sum = 12
I'm able to write an external functor for sum()
that accomplishes this, but I would really like for it to be a static constexpr
member function as above. Is this even possible in C++11?
c++ c++11 templates c++17 template-meta-programming
What is the most concise way to write the below static constexpr size_t Foo<>::sum()
method in C++11? This works fine with C++17 compilers, but I'm looking for a way that works on g++, clang, and Visual Studio 2015 in C++11 mode.
#include <iostream>
#include <type_traits>
template<typename T,size_t N>
class Foo
{
public:
static constexpr size_t sum();
};
template<typename>
struct is_foo : std::false_type { };
template<typename T,size_t N>
struct is_foo<Foo<T,N>> : std::true_type { };
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
if constexpr (is_foo<T>::value)
return N + T::sum();
else
return N;
}
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
Compile and run:
$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
...
$ g++ -std=c++17 sum.cpp
$ ./a.out
sum = 12
I'm able to write an external functor for sum()
that accomplishes this, but I would really like for it to be a static constexpr
member function as above. Is this even possible in C++11?
c++ c++11 templates c++17 template-meta-programming
c++ c++11 templates c++17 template-meta-programming
edited Jan 1 at 22:09
max66
37.9k74471
37.9k74471
asked Jan 1 at 21:08
MattMatt
15.6k13751
15.6k13751
You're just asking how to replace theif constexpr
then, right?enable_if
?
– Lightness Races in Orbit
Jan 1 at 21:19
I tried SFINAE withconstexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum()
but am getting the errorprototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'
.
– Matt
Jan 2 at 15:59
add a comment |
You're just asking how to replace theif constexpr
then, right?enable_if
?
– Lightness Races in Orbit
Jan 1 at 21:19
I tried SFINAE withconstexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum()
but am getting the errorprototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'
.
– Matt
Jan 2 at 15:59
You're just asking how to replace the
if constexpr
then, right? enable_if
?– Lightness Races in Orbit
Jan 1 at 21:19
You're just asking how to replace the
if constexpr
then, right? enable_if
?– Lightness Races in Orbit
Jan 1 at 21:19
I tried SFINAE with
constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum()
but am getting the error prototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'
.– Matt
Jan 2 at 15:59
I tried SFINAE with
constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum()
but am getting the error prototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'
.– Matt
Jan 2 at 15:59
add a comment |
4 Answers
4
active
oldest
votes
I'd write it as following:
template <typename>
struct foo_sum : std::integral_constant<size_t, 0> {};
template <typename T, size_t N>
struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};
It can be wrapped into a static constexpr
function easily:
template <typename T, size_t N>
constexpr size_t Foo<T, N>::sum()
{
return foo_sum<Foo<T, N>>::value;
}
This is nice...
– jrok
Jan 1 at 21:48
This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!
– Matt
Jan 3 at 1:53
add a comment |
An alternative approach to HolyBlackCat's answer is to use function overloading:
template <typename> struct tag {};
template <typename T>
constexpr size_t sum(tag<T>) {
return 0;
}
template <typename T, size_t N>
constexpr size_t sum(tag<Foo<T,N>>) {
return sum(tag<T>{}) + N;
}
Might be a little easier on the eyes. Could also make the functions return integral_constant
s instead of size_t
, which has some benefits.
add a comment |
With tag dispatching:
template<typename T,size_t N>
class Foo
{
static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
static constexpr size_t sum_impl(std::false_type) { return N; };
public:
static constexpr size_t sum();
};
Implementation of sum
:
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
return sum_impl( is_foo<T>{} );
}
I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compilesum_impl(std::true_type)
and results in a compiler error when T=double.
– Matt
Jan 1 at 21:34
@Matt Shame. This example seems to work with newer MSVC.
– jrok
Jan 1 at 21:45
@Matt Try making the firstsum_impl
a template itself.
– jrok
Jan 1 at 21:53
add a comment |
What about specializing the full Foo
class ?
You can also avoid is_foo
.
#include <iostream>
#include <type_traits>
template <typename, std::size_t N>
struct Foo
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Foo<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
-- EDIT --
The OP ask:
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
Not necessarily: you can do the trick with a base class/struct of Foo
(Bar
, in the following example)
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
struct Foo;
template <typename, std::size_t N>
struct Bar
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Bar<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
template <typename T, std::size_t N>
struct Foo : public Bar<T, N>
{ /* many common member and methods */};
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
– Matt
Jan 1 at 21:53
@Matt - answer improved; hope this helps.
– max66
Jan 1 at 21:59
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%2f53998958%2fhow-to-write-this-c17-static-constexpr-method-in-c11%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
I'd write it as following:
template <typename>
struct foo_sum : std::integral_constant<size_t, 0> {};
template <typename T, size_t N>
struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};
It can be wrapped into a static constexpr
function easily:
template <typename T, size_t N>
constexpr size_t Foo<T, N>::sum()
{
return foo_sum<Foo<T, N>>::value;
}
This is nice...
– jrok
Jan 1 at 21:48
This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!
– Matt
Jan 3 at 1:53
add a comment |
I'd write it as following:
template <typename>
struct foo_sum : std::integral_constant<size_t, 0> {};
template <typename T, size_t N>
struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};
It can be wrapped into a static constexpr
function easily:
template <typename T, size_t N>
constexpr size_t Foo<T, N>::sum()
{
return foo_sum<Foo<T, N>>::value;
}
This is nice...
– jrok
Jan 1 at 21:48
This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!
– Matt
Jan 3 at 1:53
add a comment |
I'd write it as following:
template <typename>
struct foo_sum : std::integral_constant<size_t, 0> {};
template <typename T, size_t N>
struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};
It can be wrapped into a static constexpr
function easily:
template <typename T, size_t N>
constexpr size_t Foo<T, N>::sum()
{
return foo_sum<Foo<T, N>>::value;
}
I'd write it as following:
template <typename>
struct foo_sum : std::integral_constant<size_t, 0> {};
template <typename T, size_t N>
struct foo_sum<Foo<T, N>> : std::integral_constant<size_t, foo_sum<T>::value + N> {};
It can be wrapped into a static constexpr
function easily:
template <typename T, size_t N>
constexpr size_t Foo<T, N>::sum()
{
return foo_sum<Foo<T, N>>::value;
}
answered Jan 1 at 21:19
HolyBlackCatHolyBlackCat
16.8k33468
16.8k33468
This is nice...
– jrok
Jan 1 at 21:48
This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!
– Matt
Jan 3 at 1:53
add a comment |
This is nice...
– jrok
Jan 1 at 21:48
This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!
– Matt
Jan 3 at 1:53
This is nice...
– jrok
Jan 1 at 21:48
This is nice...
– jrok
Jan 1 at 21:48
This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!
– Matt
Jan 3 at 1:53
This does work. On Visual Studio 2015, I was getting the infamous C1001 fatal error but through shuffling some surrounding code, it compiled. Never encountered a problem with gcc or clang. Thank you!
– Matt
Jan 3 at 1:53
add a comment |
An alternative approach to HolyBlackCat's answer is to use function overloading:
template <typename> struct tag {};
template <typename T>
constexpr size_t sum(tag<T>) {
return 0;
}
template <typename T, size_t N>
constexpr size_t sum(tag<Foo<T,N>>) {
return sum(tag<T>{}) + N;
}
Might be a little easier on the eyes. Could also make the functions return integral_constant
s instead of size_t
, which has some benefits.
add a comment |
An alternative approach to HolyBlackCat's answer is to use function overloading:
template <typename> struct tag {};
template <typename T>
constexpr size_t sum(tag<T>) {
return 0;
}
template <typename T, size_t N>
constexpr size_t sum(tag<Foo<T,N>>) {
return sum(tag<T>{}) + N;
}
Might be a little easier on the eyes. Could also make the functions return integral_constant
s instead of size_t
, which has some benefits.
add a comment |
An alternative approach to HolyBlackCat's answer is to use function overloading:
template <typename> struct tag {};
template <typename T>
constexpr size_t sum(tag<T>) {
return 0;
}
template <typename T, size_t N>
constexpr size_t sum(tag<Foo<T,N>>) {
return sum(tag<T>{}) + N;
}
Might be a little easier on the eyes. Could also make the functions return integral_constant
s instead of size_t
, which has some benefits.
An alternative approach to HolyBlackCat's answer is to use function overloading:
template <typename> struct tag {};
template <typename T>
constexpr size_t sum(tag<T>) {
return 0;
}
template <typename T, size_t N>
constexpr size_t sum(tag<Foo<T,N>>) {
return sum(tag<T>{}) + N;
}
Might be a little easier on the eyes. Could also make the functions return integral_constant
s instead of size_t
, which has some benefits.
answered Jan 1 at 23:36
BarryBarry
184k21323593
184k21323593
add a comment |
add a comment |
With tag dispatching:
template<typename T,size_t N>
class Foo
{
static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
static constexpr size_t sum_impl(std::false_type) { return N; };
public:
static constexpr size_t sum();
};
Implementation of sum
:
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
return sum_impl( is_foo<T>{} );
}
I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compilesum_impl(std::true_type)
and results in a compiler error when T=double.
– Matt
Jan 1 at 21:34
@Matt Shame. This example seems to work with newer MSVC.
– jrok
Jan 1 at 21:45
@Matt Try making the firstsum_impl
a template itself.
– jrok
Jan 1 at 21:53
add a comment |
With tag dispatching:
template<typename T,size_t N>
class Foo
{
static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
static constexpr size_t sum_impl(std::false_type) { return N; };
public:
static constexpr size_t sum();
};
Implementation of sum
:
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
return sum_impl( is_foo<T>{} );
}
I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compilesum_impl(std::true_type)
and results in a compiler error when T=double.
– Matt
Jan 1 at 21:34
@Matt Shame. This example seems to work with newer MSVC.
– jrok
Jan 1 at 21:45
@Matt Try making the firstsum_impl
a template itself.
– jrok
Jan 1 at 21:53
add a comment |
With tag dispatching:
template<typename T,size_t N>
class Foo
{
static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
static constexpr size_t sum_impl(std::false_type) { return N; };
public:
static constexpr size_t sum();
};
Implementation of sum
:
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
return sum_impl( is_foo<T>{} );
}
With tag dispatching:
template<typename T,size_t N>
class Foo
{
static constexpr size_t sum_impl(std::true_type) { return N + T::sum(); }
static constexpr size_t sum_impl(std::false_type) { return N; };
public:
static constexpr size_t sum();
};
Implementation of sum
:
template<typename T,size_t N>
constexpr size_t Foo<T,N>::sum()
{
return sum_impl( is_foo<T>{} );
}
answered Jan 1 at 21:29
jrokjrok
45.7k687121
45.7k687121
I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compilesum_impl(std::true_type)
and results in a compiler error when T=double.
– Matt
Jan 1 at 21:34
@Matt Shame. This example seems to work with newer MSVC.
– jrok
Jan 1 at 21:45
@Matt Try making the firstsum_impl
a template itself.
– jrok
Jan 1 at 21:53
add a comment |
I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compilesum_impl(std::true_type)
and results in a compiler error when T=double.
– Matt
Jan 1 at 21:34
@Matt Shame. This example seems to work with newer MSVC.
– jrok
Jan 1 at 21:45
@Matt Try making the firstsum_impl
a template itself.
– jrok
Jan 1 at 21:53
I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile
sum_impl(std::true_type)
and results in a compiler error when T=double.– Matt
Jan 1 at 21:34
I've tried this approach, and indeed it does work on g++ and clang. For some reason, Visual Studio 2015 still tries to compile
sum_impl(std::true_type)
and results in a compiler error when T=double.– Matt
Jan 1 at 21:34
@Matt Shame. This example seems to work with newer MSVC.
– jrok
Jan 1 at 21:45
@Matt Shame. This example seems to work with newer MSVC.
– jrok
Jan 1 at 21:45
@Matt Try making the first
sum_impl
a template itself.– jrok
Jan 1 at 21:53
@Matt Try making the first
sum_impl
a template itself.– jrok
Jan 1 at 21:53
add a comment |
What about specializing the full Foo
class ?
You can also avoid is_foo
.
#include <iostream>
#include <type_traits>
template <typename, std::size_t N>
struct Foo
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Foo<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
-- EDIT --
The OP ask:
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
Not necessarily: you can do the trick with a base class/struct of Foo
(Bar
, in the following example)
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
struct Foo;
template <typename, std::size_t N>
struct Bar
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Bar<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
template <typename T, std::size_t N>
struct Foo : public Bar<T, N>
{ /* many common member and methods */};
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
– Matt
Jan 1 at 21:53
@Matt - answer improved; hope this helps.
– max66
Jan 1 at 21:59
add a comment |
What about specializing the full Foo
class ?
You can also avoid is_foo
.
#include <iostream>
#include <type_traits>
template <typename, std::size_t N>
struct Foo
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Foo<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
-- EDIT --
The OP ask:
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
Not necessarily: you can do the trick with a base class/struct of Foo
(Bar
, in the following example)
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
struct Foo;
template <typename, std::size_t N>
struct Bar
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Bar<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
template <typename T, std::size_t N>
struct Foo : public Bar<T, N>
{ /* many common member and methods */};
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
– Matt
Jan 1 at 21:53
@Matt - answer improved; hope this helps.
– max66
Jan 1 at 21:59
add a comment |
What about specializing the full Foo
class ?
You can also avoid is_foo
.
#include <iostream>
#include <type_traits>
template <typename, std::size_t N>
struct Foo
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Foo<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
-- EDIT --
The OP ask:
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
Not necessarily: you can do the trick with a base class/struct of Foo
(Bar
, in the following example)
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
struct Foo;
template <typename, std::size_t N>
struct Bar
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Bar<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
template <typename T, std::size_t N>
struct Foo : public Bar<T, N>
{ /* many common member and methods */};
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
What about specializing the full Foo
class ?
You can also avoid is_foo
.
#include <iostream>
#include <type_traits>
template <typename, std::size_t N>
struct Foo
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Foo<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
-- EDIT --
The OP ask:
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
Not necessarily: you can do the trick with a base class/struct of Foo
(Bar
, in the following example)
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
struct Foo;
template <typename, std::size_t N>
struct Bar
{ static constexpr std::size_t sum () { return N; } };
template <typename T, std::size_t N1, std::size_t N2>
struct Bar<Foo<T, N1>, N2>
{ static constexpr std::size_t sum () { return Foo<T, N1>::sum() + N2; } };
template <typename T, std::size_t N>
struct Foo : public Bar<T, N>
{ /* many common member and methods */};
int main()
{
constexpr size_t sum = Foo<Foo<Foo<double,3>,4>,5>::sum(); // 12 = 3+4+5
std::cout << "sum = " << sum << std::endl;
return 0;
}
edited Jan 1 at 21:59
answered Jan 1 at 21:30
max66max66
37.9k74471
37.9k74471
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
– Matt
Jan 1 at 21:53
@Matt - answer improved; hope this helps.
– max66
Jan 1 at 21:59
add a comment |
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
– Matt
Jan 1 at 21:53
@Matt - answer improved; hope this helps.
– max66
Jan 1 at 21:59
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
– Matt
Jan 1 at 21:53
In practice, Foo is a large class with many member functions. Would this require redeclaring all of them?
– Matt
Jan 1 at 21:53
@Matt - answer improved; hope this helps.
– max66
Jan 1 at 21:59
@Matt - answer improved; hope this helps.
– max66
Jan 1 at 21:59
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%2f53998958%2fhow-to-write-this-c17-static-constexpr-method-in-c11%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
You're just asking how to replace the
if constexpr
then, right?enable_if
?– Lightness Races in Orbit
Jan 1 at 21:19
I tried SFINAE with
constexpr typename std::enable_if<is_foo<T>::value,size_t>::type Foo<T,N>::sum()
but am getting the errorprototype for 'constexpr typename std::enable_if<is_foo< <template-parameter-1-1> >::value, long unsigned int>::type Foo<T, N>::sum()' does not match any in class 'Foo<T, N>'
.– Matt
Jan 2 at 15:59