You should be using the template_include filter for this:
add_filter('template_include', 'wpse_44239_template_include', 1, 1);
function wpse_44239_template_include($template){
global $wp_query;
//Do your processing here and define $template as the full path to your alt template.
return $template;
}
template_redirect
is the action called directly before headers are sent for the output of the rendered template. It’s a convenient hook to do 404 redirects, etc… but shouldn’t be used for including other templates paths as WordPress does this innately with the ‘template_include’ filter.
template_include
and single_template
hooks deal ONLY with the path of the template used for rendering the content. This is the proper place to adjust a template path.
Update from comment by @ChipBennett:
single_template
has been removed as of 3.4. Use {posttype}_template instead.