3

Consider the following function :

template <typename Type>
void f(const Type& x)

I would like to do something special (without specialization) in it whether the passed type is an empty std::tuple or an empty std::array. For a tuple of nu elements, I can use std::is_same<Type, std::tuple<>>::value but what trick can I use to detect an zero-element array ?

(I am searching for a solution that do not require the creation of another function or class, ...)

5
  • How do you define "empty"? Commented Mar 19, 2013 at 21:03
  • std::array<Something, 0> Commented Mar 19, 2013 at 21:04
  • 6
    It may help guide answers if you can describe why you want "special without specialization" Commented Mar 19, 2013 at 21:06
  • Because it is obvious to do it with specialization, and I consider this as a "theoretical" question and I would like to know if there exist a trick (special use with of type_traits for example) that I do not know to do this kind of things. Commented Mar 19, 2013 at 21:09
  • 1
    std::array has a member function empty(), which happens to be declared constexpr. Is that what you want? Commented Mar 19, 2013 at 21:09

2 Answers 2

6

You can use std::tuple_size, as it will also work for std::array! See here. Simply use:

std::tuple_size<Type>::value == 0

to check if Type is an empty std::tuple<> or an empty std::array<T,0>.


With the above, the question remains what happens if Type is neither a std::tuple not a std::array. The general approach I see is this:

constexpr bool IsNotTupleOrArray =
  !std::is_class<Type>::value ||
  std::is_same<Type,ExcludeThisClass>::value ||
  sizeof(Type)>1 || // non-portable, works for GCC 4.8+
  ...;

std::conditional< IsNotTupleOrArray,
                  std::false_type,
                  std::tuple_size<Type> >::type::value;

which basically means that you have to explicitly exclude other types. For example is_class<Type> excludes all fundamental types like int, pointers, etc.

Sign up to request clarification or add additional context in comments.

4 Comments

Fine but what will be the result if Type is neither a tuple or an array ?
@Vincent: Without additional functions or classes, I wouldn't know how to describe your situation without using the word "doomed"...
@Vincent: Although... what exactly could Type be? Anything? Or only a limited set of other types? Please clarify the rules of this game :)
@Vincent: I went ahead and edited the answer. Note you can add a condition like sizeof(Type)>sizeof(int) as a non-portable test to exclude further types.
3

If you don't want to do it without specialization, why not doing it with overload? ;) Specializing a function template is sometimes (no, often) a bad idea. With some SFINAE trick it wouldn't be difficult to create an overload that is selected only when those two conditions apply.

However, I already hear you shouting that it's not what you wanted to do: what you wanted is some kind of if inside of f() that would be executed in case the condition is true, and a corresponding else branch that would be executed when the condition is false.

However, notice that this would not be a static if, but a regular run-time if: in other words, the compiler would know at compile-time with 100% certainty that one of those two branches is never going to be executed (and it would probably issue an annoying warning about it), but it will have to parse both branches and prove them legal.

In practice, this means that you won't be able to put statements that depend on the particular type T (or on properties of T) in order to be compilable. For instance, in the code below compile_time_expression determines whether type T has a member function foo() or a member function bar():

T obj;
if (compile_time_expression)
{
    obj.foo();
}
else
{
    obj.bar();
}

However, the above won't compile if that particular T doesn't have both a member function foo() and a member function bar(): since what you have here is a run-time if, the compiler will have to parse both branches and make sure they're both compilable - and then possibly optimize away the one that is never going to be executed.

Unfortunately, C++ does not have any construct such as static if (yet?), so overloading + SFINAE is the right way to tackle this problem.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.